mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	Merge branch 'delcypher-cmake_fix_enable_tracing_in_debug_mode'
This commit is contained in:
		
						commit
						38fc49a05d
					
				
					 97 changed files with 6621 additions and 845 deletions
				
			
		|  | @ -289,12 +289,14 @@ endif() | |||
| ################################################################################ | ||||
| # Tracing | ||||
| ################################################################################ | ||||
| option(ENABLE_TRACING OFF "Enable tracing") | ||||
| if (ENABLE_TRACING) | ||||
| option(ENABLE_TRACING_FOR_NON_DEBUG "Enable tracing in non-debug builds." OFF) | ||||
| if (ENABLE_TRACING_FOR_NON_DEBUG) | ||||
|   list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_TRACE") | ||||
| else() | ||||
|   # Tracing is always enabled in debug builds | ||||
|   list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:_TRACE>) | ||||
| endif() | ||||
| # Should we always enable tracing when doing a debug build? | ||||
| #list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:_TRACE>) | ||||
| 
 | ||||
| ################################################################################ | ||||
| # Postion indepdent code | ||||
|  |  | |||
|  | @ -265,7 +265,8 @@ The following useful options can be passed to CMake whilst configuring. | |||
| * ``CMAKE_INSTALL_INCLUDEDIR`` - STRING. The path to install z3 include files (relative to ``CMAKE_INSTALL_PREFIX``), e.g. ``include``. | ||||
| * ``CMAKE_INSTALL_LIBDIR`` - STRING. The path to install z3 libraries (relative to ``CMAKE_INSTALL_PREFIX``), e.g. ``lib``. | ||||
| * ``CMAKE_INSTALL_PREFIX`` - STRING. The install prefix to use (e.g. ``/usr/local/``). | ||||
| * ``ENABLE_TRACING`` - BOOL. If set to ``TRUE`` enable tracing, if set to ``FALSE`` disable tracing. | ||||
| * ``CMAKE_INSTALL_PYTHON_PKG_DIR`` - STRING. The path to install the z3 python bindings. This can be relative (to ``CMAKE_INSTALL_PREFIX``) or absolute. | ||||
| * ``ENABLE_TRACING_FOR_NON_DEBUG`` - BOOL. If set to ``TRUE`` enable tracing in non-debug builds, if set to ``FALSE`` disable tracing in non-debug builds. Note in debug builds tracing is always enabled. | ||||
| * ``BUILD_LIBZ3_SHARED`` - BOOL. If set to ``TRUE`` build libz3 as a shared library otherwise build as a static library. | ||||
| * ``ENABLE_EXAMPLE_TARGETS`` - BOOL. If set to ``TRUE`` add the build targets for building the API examples. | ||||
| * ``USE_OPENMP`` - BOOL. If set to ``TRUE`` and OpenMP support is detected build with OpenMP support. | ||||
|  |  | |||
|  | @ -74,35 +74,50 @@ add_custom_target(build_z3_python_bindings | |||
| ############################################################################### | ||||
| option(INSTALL_PYTHON_BINDINGS "Install Python bindings when invoking install target" ON) | ||||
| if (INSTALL_PYTHON_BINDINGS) | ||||
|   # Determine the installation path for the bindings | ||||
|   message(STATUS "Emitting rules to install Z3 python bindings") | ||||
|   execute_process( | ||||
|     COMMAND "${PYTHON_EXECUTABLE}" "-c" | ||||
|       "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())" | ||||
|     RESULT_VARIABLE exit_code | ||||
|     OUTPUT_VARIABLE python_pkg_dir | ||||
|     OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
|   ) | ||||
|   # Try to guess the installation path for the bindings | ||||
|   if (NOT DEFINED CMAKE_INSTALL_PYTHON_PKG_DIR) | ||||
|     message(STATUS "CMAKE_INSTALL_PYTHON_PKG_DIR not set. Trying to guess") | ||||
|     execute_process( | ||||
|       COMMAND "${PYTHON_EXECUTABLE}" "-c" | ||||
|         "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())" | ||||
|       RESULT_VARIABLE exit_code | ||||
|       OUTPUT_VARIABLE CMAKE_INSTALL_PYTHON_PKG_DIR | ||||
|       OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
|     ) | ||||
| 
 | ||||
|   if (NOT ("${exit_code}" EQUAL 0)) | ||||
|     message(FATAL_ERROR "Failed to determine your Python package directory") | ||||
|     if (NOT ("${exit_code}" EQUAL 0)) | ||||
|       message(FATAL_ERROR "Failed to determine your Python package directory") | ||||
|     endif() | ||||
|     message(STATUS "Detected Python package directory: \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\"") | ||||
|     # Set a cache variable that the user can modify if needed | ||||
|     set(CMAKE_INSTALL_PYTHON_PKG_DIR | ||||
|       "${CMAKE_INSTALL_PYTHON_PKG_DIR}" | ||||
|       CACHE PATH | ||||
|       "Path to install python bindings. This can be relative or absolute.") | ||||
|     mark_as_advanced(CMAKE_INSTALL_PYTHON_PKG_DIR) | ||||
|   else() | ||||
|     message(STATUS "CMAKE_INSTALL_PYTHON_PKG_DIR already set (\"${CMAKE_INSTALL_PYTHON_PKG_DIR}\")" | ||||
|                    ". Not trying to guess.") | ||||
|   endif() | ||||
|   message(STATUS "Detected Python package directory: \"${python_pkg_dir}\"") | ||||
| 
 | ||||
|   # Check if path exists under the install prefix | ||||
|   set(python_install_dir "") | ||||
|   string(FIND "${python_pkg_dir}" "${CMAKE_INSTALL_PREFIX}" position) | ||||
|   if (NOT ("${position}" EQUAL 0)) | ||||
|     message(WARNING "The detected Python package directory \"${python_pkg_dir}\" " | ||||
|             "does not exist under the install prefix \"${CMAKE_INSTALL_PREFIX}\"." | ||||
|             " Running the install target may lead to a broken installation." | ||||
|            ) | ||||
|   # Check if path exists under the install prefix if it is absolute. If the | ||||
|   # path is relative it will be installed under the install prefix so there | ||||
|   # if nothing to check | ||||
|   if (IS_ABSOLUTE "${CMAKE_INSTALL_PYTHON_PKG_DIR}") | ||||
|     string(FIND "${CMAKE_INSTALL_PYTHON_PKG_DIR}" "${CMAKE_INSTALL_PREFIX}" position) | ||||
|     if (NOT ("${position}" EQUAL 0)) | ||||
|       message(WARNING "The directory to install the python bindings \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\" " | ||||
|               "is not under the install prefix \"${CMAKE_INSTALL_PREFIX}\"." | ||||
|               " Running the install target may lead to a broken installation. " | ||||
|               "To change the install directory modify the CMAKE_INSTALL_PYTHON_PKG_DIR cache variable." | ||||
|               ) | ||||
|     endif() | ||||
|   endif() | ||||
|   # Using DESTDIR still seems to work even if we use an absolute path | ||||
|   set(python_install_dir "${python_pkg_dir}") | ||||
|   message(STATUS "Python bindings will be installed to \"${python_install_dir}\"") | ||||
|   message(STATUS "Python bindings will be installed to \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\"") | ||||
|   install(FILES ${build_z3_python_bindings_target_depends} | ||||
|     DESTINATION "${python_install_dir}" | ||||
|     DESTINATION "${CMAKE_INSTALL_PYTHON_PKG_DIR}" | ||||
|   ) | ||||
| else() | ||||
|   message(STATUS "Not emitting rules to install Z3 python bindings") | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ z3_add_component(rewriter | |||
|     expr_safe_replace.cpp | ||||
|     factor_rewriter.cpp | ||||
|     fpa_rewriter.cpp | ||||
|     label_rewriter.cpp | ||||
|     mk_simplified_app.cpp | ||||
|     pb_rewriter.cpp | ||||
|     quant_hoist.cpp | ||||
|  |  | |||
|  | @ -1,21 +1,28 @@ | |||
| z3_add_component(qe | ||||
|   SOURCES | ||||
|     nlarith_util.cpp | ||||
|     nlqsat.cpp | ||||
|     qe_arith.cpp | ||||
|     qe_arith_plugin.cpp | ||||
|     qe_array_plugin.cpp | ||||
|     qe_arrays.cpp | ||||
|     qe_bool_plugin.cpp | ||||
|     qe_bv_plugin.cpp | ||||
|     qe_cmd.cpp | ||||
|     qe.cpp | ||||
|     qe_datatype_plugin.cpp | ||||
|     qe_datatypes.cpp | ||||
|     qe_dl_plugin.cpp | ||||
|     qe_lite.cpp | ||||
|     qe_mbp.cpp | ||||
|     qe_sat_tactic.cpp | ||||
|     qe_tactic.cpp | ||||
|     qe_util.cpp | ||||
|     qsat.cpp | ||||
|     vsubst_tactic.cpp | ||||
|   COMPONENT_DEPENDENCIES | ||||
|     nlsat_tactic | ||||
|     nlsat | ||||
|     sat | ||||
|     smt | ||||
|     smt    | ||||
|     tactic  | ||||
| ) | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ def sorted_headers_by_component(l): | |||
|         _logger.debug("get_key({})".format(path)) | ||||
|         path_components = [] | ||||
|         stripped_path = path | ||||
|         assert 'src' in stripped_path.split(os.path.sep) | ||||
|         assert 'src' in stripped_path.split(os.path.sep) or 'src' in stripped_path.split('/') | ||||
|         # Keep stripping off directory components until we hit ``src`` | ||||
|         while os.path.basename(stripped_path) != 'src': | ||||
|             path_components.append(os.path.basename(stripped_path)) | ||||
|  | @ -214,7 +214,7 @@ def mk_gparams_register_modules_internal(component_src_dirs, path): | |||
|     """ | ||||
|     assert isinstance(component_src_dirs, list) | ||||
|     assert check_dir_exists(path) | ||||
|     cmds = [] | ||||
|     cmds = []     | ||||
|     mod_cmds = [] | ||||
|     mod_descrs = [] | ||||
|     fullname = os.path.join(path, 'gparams_register_modules.cpp') | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ def init_project_def(): | |||
|     add_lib('fuzzing', ['ast'], 'test/fuzzing') | ||||
|     add_lib('smt_tactic', ['smt'], 'smt/tactic') | ||||
|     add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') | ||||
|     add_lib('qe', ['smt','sat'], 'qe') | ||||
|     add_lib('qe', ['smt','sat','nlsat','tactic','nlsat_tactic'], 'qe') | ||||
|     add_lib('duality', ['smt', 'interp', 'qe']) | ||||
|     add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base') | ||||
|     add_lib('dataflow', ['muz'], 'muz/dataflow') | ||||
|  |  | |||
|  | @ -604,8 +604,16 @@ namespace z3 { | |||
| 
 | ||||
|         /**
 | ||||
|            \brief Return true if this expression is a numeral. | ||||
|            Specialized functions also return representations for the numerals as | ||||
|            small integers, 64 bit integers or rational or decimal strings. | ||||
|         */ | ||||
|         bool is_numeral() const { return kind() == Z3_NUMERAL_AST; } | ||||
|         bool is_numeral_i64(__int64& i) const { bool r = 0 != Z3_get_numeral_int64(ctx(), m_ast, &i); check_error(); return r;} | ||||
|         bool is_numeral_u64(__uint64& i) const { bool r = 0 != Z3_get_numeral_uint64(ctx(), m_ast, &i); check_error(); return r;} | ||||
|         bool is_numeral_i(int& i) const { bool r = 0 != Z3_get_numeral_int(ctx(), m_ast, &i); check_error(); return r;} | ||||
|         bool is_numeral_u(unsigned& i) const { bool r = 0 != Z3_get_numeral_uint(ctx(), m_ast, &i); check_error(); return r;} | ||||
|         bool is_numeral(std::string& s) const { if (!is_numeral()) return false; s = Z3_get_numeral_string(ctx(), m_ast); check_error(); return true; } | ||||
|         bool is_numeral(std::string& s, unsigned precision) const { if (!is_numeral()) return false; s = Z3_get_numeral_decimal_string(ctx(), m_ast, precision); check_error(); return true; } | ||||
|         /**
 | ||||
|            \brief Return true if this expression is an application. | ||||
|         */ | ||||
|  | @ -625,7 +633,7 @@ namespace z3 { | |||
|         /**
 | ||||
|            \brief Return true if expression is an algebraic number. | ||||
|         */ | ||||
|         bool is_algebraic() const { return Z3_is_algebraic_number(ctx(), m_ast); } | ||||
|         bool is_algebraic() const { return 0 != Z3_is_algebraic_number(ctx(), m_ast); } | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Return true if this expression is well sorted (aka type correct). | ||||
|  | @ -649,12 +657,11 @@ namespace z3 { | |||
|             | ||||
|            \pre is_numeral() | ||||
|         */ | ||||
|         int get_numeral_int() const { | ||||
|             assert(is_numeral()); | ||||
|         int get_numeral_int() const {              | ||||
|             int result; | ||||
|             Z3_bool state = Z3_get_numeral_int(ctx(), m_ast, &result); | ||||
|             if (state != Z3_TRUE) | ||||
|             if (!is_numeral_i(result)) { | ||||
|                 throw exception("numeral does not fit in machine int"); | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|          | ||||
|  | @ -667,9 +674,9 @@ namespace z3 { | |||
|         unsigned get_numeral_uint() const { | ||||
|             assert(is_numeral()); | ||||
|             unsigned result; | ||||
|             Z3_bool state = Z3_get_numeral_uint(ctx(), m_ast, &result); | ||||
|             if (state != Z3_TRUE) | ||||
|             if (!is_numeral_u(result)) { | ||||
|                 throw exception("numeral does not fit in machine uint"); | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|          | ||||
|  | @ -682,9 +689,9 @@ namespace z3 { | |||
|         __int64 get_numeral_int64() const { | ||||
|             assert(is_numeral()); | ||||
|             __int64 result; | ||||
|             Z3_bool state = Z3_get_numeral_int64(ctx(), m_ast, &result); | ||||
|             if (state != Z3_TRUE) | ||||
|             if (!is_numeral_i64(result)) { | ||||
|                 throw exception("numeral does not fit in machine __int64"); | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|          | ||||
|  | @ -697,9 +704,9 @@ namespace z3 { | |||
|         __uint64 get_numeral_uint64() const { | ||||
|             assert(is_numeral()); | ||||
|             __uint64 result; | ||||
|             Z3_bool state = Z3_get_numeral_uint64(ctx(), m_ast, &result); | ||||
|             if (state != Z3_TRUE) | ||||
|             if (!is_numeral_u64(result)) { | ||||
|                 throw exception("numeral does not fit in machine __uint64"); | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|             | ||||
|  |  | |||
|  | @ -3940,7 +3940,7 @@ class ArraySortRef(SortRef): | |||
|         >>> A.range() | ||||
|         Bool | ||||
|         """ | ||||
|         return _to_sort_ref(Z3_get_array_sort_range(self.ctx_ref(), self.ast), self.ctx) | ||||
|         return _to_sort_ref(Z3_get_array_sort_range(self.ctx_ref(), self.ast), self.ctx)     | ||||
| 
 | ||||
| class ArrayRef(ExprRef): | ||||
|     """Array expressions. """ | ||||
|  | @ -4162,6 +4162,7 @@ def Select(a, i): | |||
|         _z3_assert(is_array(a), "First argument must be a Z3 array expression") | ||||
|     return a[i] | ||||
| 
 | ||||
|      | ||||
| def Map(f, *args): | ||||
|     """Return a Z3 map array expression. | ||||
| 
 | ||||
|  |  | |||
|  | @ -664,3 +664,45 @@ algebraic_numbers::anum const & arith_util::to_irrational_algebraic_numeral(expr | |||
|     SASSERT(is_irrational_algebraic_numeral(n)); | ||||
|     return plugin().aw().to_anum(to_app(n)->get_decl()); | ||||
| } | ||||
| 
 | ||||
| expr_ref arith_util::mk_mul_simplify(expr_ref_vector const& args) { | ||||
|     return mk_mul_simplify(args.size(), args.c_ptr()); | ||||
| 
 | ||||
| } | ||||
| expr_ref arith_util::mk_mul_simplify(unsigned sz, expr* const* args) { | ||||
|     expr_ref result(m_manager); | ||||
|      | ||||
|     switch (sz) { | ||||
|     case 0: | ||||
|         result = mk_numeral(rational(1), true); | ||||
|         break; | ||||
|     case 1: | ||||
|         result = args[0]; | ||||
|         break; | ||||
|     default: | ||||
|         result = mk_mul(sz, args); | ||||
|         break;                     | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| expr_ref arith_util::mk_add_simplify(expr_ref_vector const& args) { | ||||
|     return mk_add_simplify(args.size(), args.c_ptr()); | ||||
| 
 | ||||
| } | ||||
| expr_ref arith_util::mk_add_simplify(unsigned sz, expr* const* args) { | ||||
|     expr_ref result(m_manager); | ||||
|      | ||||
|     switch (sz) { | ||||
|     case 0: | ||||
|         result = mk_numeral(rational(0), true); | ||||
|         break; | ||||
|     case 1: | ||||
|         result = args[0]; | ||||
|         break; | ||||
|     default: | ||||
|         result = mk_add(sz, args); | ||||
|         break;                     | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
|  |  | |||
|  | @ -149,7 +149,6 @@ protected: | |||
|     func_decl * m_mod_0_decl; | ||||
|     func_decl * m_u_asin_decl; | ||||
|     func_decl * m_u_acos_decl; | ||||
| 
 | ||||
|     ptr_vector<app> m_small_ints; | ||||
|     ptr_vector<app> m_small_reals; | ||||
| 
 | ||||
|  | @ -416,6 +415,11 @@ public: | |||
|         return m_manager.mk_eq(lhs, rhs); | ||||
|     } | ||||
| 
 | ||||
|     expr_ref mk_mul_simplify(expr_ref_vector const& args); | ||||
|     expr_ref mk_mul_simplify(unsigned sz, expr* const* args); | ||||
| 
 | ||||
|     expr_ref mk_add_simplify(expr_ref_vector const& args); | ||||
|     expr_ref mk_add_simplify(unsigned sz, expr* const* args); | ||||
| }; | ||||
| 
 | ||||
| #endif /* ARITH_DECL_PLUGIN_H_ */ | ||||
|  |  | |||
|  | @ -1200,6 +1200,14 @@ std::ostream& operator<<(std::ostream& out, app_ref const&  e) { | |||
|     return out << mk_ismt2_pp(e.get(), e.get_manager()); | ||||
| } | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, func_decl_ref const&  e) { | ||||
|     return out << mk_ismt2_pp(e.get(), e.get_manager()); | ||||
| } | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, sort_ref const&  e) { | ||||
|     return out << mk_ismt2_pp(e.get(), e.get_manager()); | ||||
| } | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, expr_ref_vector const&  e) { | ||||
|     for (unsigned i = 0; i < e.size(); ++i) { | ||||
|         out << mk_ismt2_pp(e[i], e.get_manager()); | ||||
|  | @ -1216,6 +1224,18 @@ std::ostream& operator<<(std::ostream& out, app_ref_vector const&  e) { | |||
|     return out; | ||||
| } | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const&  e) { | ||||
|     for (unsigned i = 0; i < e.size(); ++i)  | ||||
|         out << mk_ismt2_pp(e[i], e.get_manager()) << "\n"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, sort_ref_vector const&  e) { | ||||
|     for (unsigned i = 0; i < e.size(); ++i)  | ||||
|         out << mk_ismt2_pp(e[i], e.get_manager()) << "\n"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| #ifdef Z3DEBUG | ||||
| void pp(expr const * n, ast_manager & m) { | ||||
|     std::cout << mk_ismt2_pp(const_cast<expr*>(n), m) << std::endl; | ||||
|  |  | |||
|  | @ -117,8 +117,13 @@ std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p); | |||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, expr_ref const& e); | ||||
| std::ostream& operator<<(std::ostream& out, app_ref const& e); | ||||
| std::ostream& operator<<(std::ostream& out, func_decl_ref const& e); | ||||
| std::ostream& operator<<(std::ostream& out, sort_ref const& e); | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e); | ||||
| std::ostream& operator<<(std::ostream& out, app_ref_vector const& e); | ||||
| std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e); | ||||
| std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -170,7 +170,6 @@ app* mk_and(ast_manager & m, unsigned num_args, app * const * args) { | |||
|     return to_app(mk_and(m, num_args, (expr* const*) args)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) { | ||||
|     if (num_args == 0) | ||||
|         return m.mk_false(); | ||||
|  | @ -188,10 +187,43 @@ expr * mk_not(ast_manager & m, expr * arg) { | |||
|     expr * atom; | ||||
|     if (m.is_not(arg, atom)) | ||||
|         return atom; | ||||
|     else if (m.is_true(arg))  | ||||
|         return m.mk_false(); | ||||
|     else if (m.is_false(arg)) | ||||
|         return m.mk_true(); | ||||
|     else | ||||
|         return m.mk_not(arg); | ||||
| } | ||||
| 
 | ||||
| expr_ref push_not(const expr_ref& e) { | ||||
|     ast_manager& m = e.get_manager(); | ||||
|     if (!is_app(e)) { | ||||
|         return expr_ref(m.mk_not(e), m); | ||||
|     } | ||||
|     app* a = to_app(e); | ||||
|     if (m.is_and(a)) { | ||||
|         if (a->get_num_args() == 0) { | ||||
|             return expr_ref(m.mk_false(), m); | ||||
|         } | ||||
|         expr_ref_vector args(m); | ||||
|         for (unsigned i = 0; i < a->get_num_args(); ++i) { | ||||
|             args.push_back(push_not(expr_ref(a->get_arg(i), m))); | ||||
|         } | ||||
|         return mk_or(args); | ||||
|     } | ||||
|     if (m.is_or(a)) { | ||||
|         if (a->get_num_args() == 0) { | ||||
|             return expr_ref(m.mk_true(), m); | ||||
|         } | ||||
|         expr_ref_vector args(m); | ||||
|         for (unsigned i = 0; i < a->get_num_args(); ++i) { | ||||
|             args.push_back(push_not(expr_ref(a->get_arg(i), m))); | ||||
|         } | ||||
|         return mk_and(args); | ||||
|     } | ||||
|     return expr_ref(mk_not(m, e), m);     | ||||
| } | ||||
| 
 | ||||
| expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args) { | ||||
|     expr_ref_buffer new_diseqs(m); | ||||
|     for (unsigned i = 0; i < num_args; i++) { | ||||
|  | @ -201,6 +233,24 @@ expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args) | |||
|     return mk_and(m, new_diseqs.size(), new_diseqs.c_ptr()); | ||||
| } | ||||
| 
 | ||||
| expr* mk_distinct(ast_manager& m, unsigned num_args, expr * const * args) { | ||||
|     switch (num_args) { | ||||
|     case 0: | ||||
|     case 1: | ||||
|         return m.mk_true(); | ||||
|     case 2: | ||||
|         return m.mk_not(m.mk_eq(args[0], args[1])); | ||||
|     default: | ||||
|         return m.mk_distinct(num_args, args); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| expr_ref mk_distinct(expr_ref_vector const& args) { | ||||
|     ast_manager& m = args.get_manager(); | ||||
|     return expr_ref(mk_distinct(m, args.size(), args.c_ptr()), m); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void flatten_and(expr_ref_vector& result) { | ||||
|     ast_manager& m = result.get_manager(); | ||||
|     expr* e1, *e2, *e3; | ||||
|  |  | |||
|  | @ -121,18 +121,29 @@ app  * mk_or(ast_manager & m, unsigned num_args, app * const * args); | |||
| inline app_ref mk_or(app_ref_vector const& args) { return app_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } | ||||
| inline expr_ref mk_or(expr_ref_vector const& args) { return expr_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|    Return a          if arg = (not a) | ||||
|    Retur (not arg)   otherwise | ||||
|  */ | ||||
| expr * mk_not(ast_manager & m, expr * arg); | ||||
| 
 | ||||
| /**
 | ||||
|    Negate and push over conjunction or disjunction. | ||||
|  */ | ||||
| expr_ref push_not(const expr_ref& arg); | ||||
| 
 | ||||
| /**
 | ||||
|    Return the expression (and (not (= args[0] args[1])) (not (= args[0] args[2])) ... (not (= args[num_args-2] args[num_args-1]))) | ||||
| */ | ||||
| expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args); | ||||
| 
 | ||||
| /**
 | ||||
|    Create simplified distinct term. Binary distinct becomes a single disequality. | ||||
|  */ | ||||
| expr * mk_distinct(ast_manager& m, unsigned num_args, expr * const * args); | ||||
| 
 | ||||
| expr_ref mk_distinct(expr_ref_vector const& args); | ||||
| 
 | ||||
| /**
 | ||||
|    \brief Collect top-level conjunctions and disjunctions. | ||||
| */ | ||||
|  |  | |||
|  | @ -865,6 +865,12 @@ sort * bv_util::mk_sort(unsigned bv_size) { | |||
|     return m_manager.mk_sort(get_fid(), BV_SORT, 1, p); | ||||
| } | ||||
| 
 | ||||
| unsigned bv_util::get_int2bv_size(parameter const& p) { | ||||
|     int sz; | ||||
|     VERIFY(m_plugin->get_int2bv_size(1, &p, sz)); | ||||
|     return static_cast<unsigned>(sz); | ||||
| } | ||||
| 
 | ||||
| app * bv_util::mk_bv2int(expr* e) { | ||||
|     sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT); | ||||
|     parameter p(s); | ||||
|  |  | |||
|  | @ -234,7 +234,6 @@ protected: | |||
| 
 | ||||
|     func_decl * mk_mkbv(unsigned arity, sort * const * domain); | ||||
| 
 | ||||
|     bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result); | ||||
| 
 | ||||
|     func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity); | ||||
| 
 | ||||
|  | @ -267,6 +266,8 @@ public: | |||
| 
 | ||||
|     virtual expr * get_some_value(sort * s); | ||||
| 
 | ||||
|     bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result); | ||||
| 
 | ||||
|     virtual bool is_considered_uninterpreted(func_decl * f) { | ||||
|         if (f->get_family_id() != get_family_id()) | ||||
|             return false; | ||||
|  | @ -390,6 +391,8 @@ public: | |||
|         return static_cast<unsigned>(s->get_parameter(0).get_int()); | ||||
|     } | ||||
|     unsigned get_bv_size(expr const * n) const { return get_bv_size(m_manager.get_sort(n)); } | ||||
|     unsigned get_int2bv_size(parameter const& p); | ||||
| 
 | ||||
| 
 | ||||
|     app * mk_ule(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_ULEQ, arg1, arg2); } | ||||
|     app * mk_sle(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLEQ, arg1, arg2); } | ||||
|  | @ -427,6 +430,7 @@ public: | |||
|     app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); } | ||||
| 
 | ||||
|     app * mk_bv(unsigned n, expr* const* es) { return m_manager.mk_app(get_fid(), OP_MKBV, n, es); } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| #endif /* BV_DECL_PLUGIN_H_ */ | ||||
|  |  | |||
|  | @ -1000,3 +1000,25 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) { | |||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool datatype_util::is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f) { | ||||
|     bool eq =  | ||||
|         f->get_decl_kind() == k && | ||||
|         f->get_family_id() == m_family_id && | ||||
|         f->get_num_parameters() == num_params; | ||||
|     for (unsigned i = 0; eq && i < num_params; ++i) { | ||||
|         eq = params[i] == f->get_parameter(i); | ||||
|     } | ||||
|     return eq; | ||||
| } | ||||
| 
 | ||||
| bool datatype_util::is_constructor_of(unsigned num_params, parameter const* params, func_decl* f) { | ||||
|     return  | ||||
|         num_params == 2 && | ||||
|         m_family_id == f->get_family_id() && | ||||
|         OP_DT_CONSTRUCTOR == f->get_decl_kind() && | ||||
|         2 == f->get_num_parameters() && | ||||
|         params[0] == f->get_parameter(0) && | ||||
|         params[1] == f->get_parameter(1); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -209,6 +209,8 @@ public: | |||
|     func_decl * get_recognizer_constructor(func_decl * recognizer); | ||||
|     family_id get_family_id() const { return m_family_id; } | ||||
|     bool are_siblings(sort * s1, sort * s2); | ||||
|     bool is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f); | ||||
|     bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f); | ||||
|     void reset(); | ||||
|     void display_datatype(sort *s, std::ostream& strm); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,6 +22,10 @@ Notes: | |||
| 
 | ||||
| void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { | ||||
|      | ||||
|     if (num_bound == 0) { | ||||
|         result = n; | ||||
|         return; | ||||
|     } | ||||
|     expr * curr = 0, *b = 0; | ||||
|     SASSERT(n->get_ref_count() > 0); | ||||
| 
 | ||||
|  | @ -106,3 +110,27 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons | |||
|     expr_abstractor abs(m); | ||||
|     abs(base, num_bound, bound, n, result); | ||||
| } | ||||
| 
 | ||||
| expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) { | ||||
|     expr_ref result(m); | ||||
|     expr_abstract(m, 0, num_bound, (expr* const*)bound, n, result);     | ||||
|     if (num_bound > 0) { | ||||
|         ptr_vector<sort> sorts; | ||||
|         svector<symbol> names; | ||||
|         for (unsigned i = 0; i < num_bound; ++i) { | ||||
|             sorts.push_back(m.get_sort(bound[i])); | ||||
|             names.push_back(bound[i]->get_decl()->get_name()); | ||||
|         } | ||||
|         result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result); | ||||
|     } | ||||
|     return result; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) { | ||||
|     return mk_quantifier(true, m, num_bound, bound, n); | ||||
| } | ||||
| 
 | ||||
| expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) { | ||||
|     return mk_quantifier(false, m, num_bound, bound, n); | ||||
| } | ||||
|  |  | |||
|  | @ -33,6 +33,8 @@ public: | |||
| }; | ||||
| 
 | ||||
| void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref&  result); | ||||
| expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n); | ||||
| expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,6 +30,14 @@ void expr_safe_replace::insert(expr* src, expr* dst) { | |||
|     m_subst.insert(src, dst); | ||||
| } | ||||
| 
 | ||||
| void expr_safe_replace::operator()(expr_ref_vector& es) { | ||||
|     expr_ref val(m); | ||||
|     for (unsigned i = 0; i < es.size(); ++i) { | ||||
|         (*this)(es[i].get(), val); | ||||
|         es[i] = val; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void expr_safe_replace::operator()(expr* e, expr_ref& res) { | ||||
|     m_todo.push_back(e); | ||||
|     expr* a, *b; | ||||
|  |  | |||
|  | @ -42,6 +42,8 @@ public: | |||
| 
 | ||||
|     void operator()(expr* src, expr_ref& e); | ||||
| 
 | ||||
|     void operator()(expr_ref_vector& es); | ||||
| 
 | ||||
|     void apply_substitution(expr* s, expr* def, expr_ref& t); | ||||
| 
 | ||||
|     void reset(); | ||||
|  |  | |||
							
								
								
									
										53
									
								
								src/ast/rewriter/label_rewriter.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/ast/rewriter/label_rewriter.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     label_rewriter.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Basic rewriting rules for removing labels. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-19-10 | ||||
| 
 | ||||
| Notes: | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #include"rewriter.h" | ||||
| #include"rewriter_def.h" | ||||
| #include"label_rewriter.h" | ||||
| 
 | ||||
| 
 | ||||
| label_rewriter::label_rewriter(ast_manager & m) :  | ||||
|     m_label_fid(m.get_label_family_id()), | ||||
|     m_rwr(m, false, *this) {} | ||||
| 
 | ||||
| label_rewriter::~label_rewriter() {} | ||||
| 
 | ||||
| br_status label_rewriter::reduce_app( | ||||
|     func_decl * f, unsigned num, expr * const * args, expr_ref & result,  | ||||
|     proof_ref & result_pr) { | ||||
|     if (is_decl_of(f, m_label_fid, OP_LABEL)) { | ||||
|         SASSERT(num == 1); | ||||
|         result = args[0]; | ||||
|         return BR_DONE; | ||||
|     } | ||||
|     return BR_FAILED; | ||||
| } | ||||
| 
 | ||||
| void label_rewriter::remove_labels(expr_ref& fml, proof_ref& pr) { | ||||
|     ast_manager& m = fml.get_manager(); | ||||
|     expr_ref tmp(m); | ||||
|     m_rwr(fml, tmp); | ||||
|     if (pr && fml != tmp) {         | ||||
|         pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp)); | ||||
|     } | ||||
|     fml = tmp; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //template class rewriter_tpl<label_rewriter>;
 | ||||
							
								
								
									
										41
									
								
								src/ast/rewriter/label_rewriter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/ast/rewriter/label_rewriter.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     label_rewriter.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Basic rewriting rules for labels. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-19-10 | ||||
| 
 | ||||
| Notes: | ||||
| 
 | ||||
| --*/ | ||||
| #ifndef LABEL_REWRITER_H_ | ||||
| #define LABEL_REWRITER_H_ | ||||
| 
 | ||||
| #include"ast.h" | ||||
| #include"rewriter_types.h" | ||||
| 
 | ||||
| 
 | ||||
| class label_rewriter : public default_rewriter_cfg { | ||||
|     family_id m_label_fid; | ||||
|     rewriter_tpl<label_rewriter> m_rwr; | ||||
| public:     | ||||
|     label_rewriter(ast_manager & m); | ||||
|     ~label_rewriter(); | ||||
| 
 | ||||
|     br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,  | ||||
|                          proof_ref & result_pr); | ||||
| 
 | ||||
|      | ||||
|     void remove_labels(expr_ref& fml, proof_ref& pr); | ||||
|      | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -73,7 +73,7 @@ public: | |||
|         unsigned nd = q->get_num_decls(); | ||||
|         for (unsigned i = 0; i < nd; ++i) { | ||||
|             sort* s = q->get_decl_sort(i); | ||||
|             app* a = m.mk_fresh_const("x", s); | ||||
|             app* a = m.mk_fresh_const(q->get_decl_name(i).str().c_str(), s); | ||||
|             vars.push_back(a); | ||||
|         } | ||||
|         expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd); | ||||
|  | @ -154,9 +154,7 @@ private: | |||
|     } | ||||
|      | ||||
|     quantifier_type& negate(quantifier_type& qt) { | ||||
|         TRACE("qe", display(qt, tout); tout << "\n";); | ||||
|         qt = static_cast<quantifier_type>(qt ^0x1); | ||||
|         TRACE("qe", display(qt, tout); tout << "\n";); | ||||
|         return qt; | ||||
|     } | ||||
|      | ||||
|  | @ -205,6 +203,7 @@ private: | |||
|         case AST_APP: { | ||||
|             expr_ref_vector args(m); | ||||
|             expr_ref tmp(m); | ||||
|             expr* t1, *t2, *t3; | ||||
|             unsigned num_args = 0; | ||||
|             app* a = to_app(fml); | ||||
|             if (m.is_and(fml)) { | ||||
|  | @ -228,16 +227,35 @@ private: | |||
|                 negate(qt); | ||||
|                 result = m.mk_not(tmp); | ||||
|             } | ||||
|             else if (m.is_implies(fml)) { | ||||
|                 pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp); | ||||
|             else if (m.is_implies(fml, t1, t2)) { | ||||
|                 pull_quantifier(t1, negate(qt), vars, tmp); | ||||
|                 negate(qt); | ||||
|                 pull_quantifier(to_app(fml)->get_arg(1), qt, vars, result); | ||||
|                 pull_quantifier(t2, qt, vars, result); | ||||
|                 result = m.mk_implies(tmp, result); | ||||
|             } | ||||
|             else if (m.is_ite(fml)) { | ||||
|                 pull_quantifier(to_app(fml)->get_arg(1), qt, vars, tmp); | ||||
|                 pull_quantifier(to_app(fml)->get_arg(2), qt, vars, result); | ||||
|                 result = m.mk_ite(to_app(fml)->get_arg(0), tmp, result); | ||||
|             else if (m.is_ite(fml, t1, t2, t3)) { | ||||
|                 expr_ref tt1(m), tt2(m), tt3(m), ntt1(m), nt1(m); | ||||
|                 pull_quantifier(t2, qt, vars, tt2); | ||||
|                 pull_quantifier(t3, qt, vars, tt3); | ||||
|                 if (has_quantifiers(t1)) { | ||||
|                     pull_quantifier(t1, qt, vars, tt1); | ||||
|                     nt1 = m.mk_not(t1); | ||||
|                     pull_quantifier(nt1, qt, vars, ntt1); | ||||
|                     result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(tt1, tt3)); | ||||
|                 } | ||||
|                 else { | ||||
|                     result = m.mk_ite(t1, tt2, tt3); | ||||
|                 } | ||||
|             } | ||||
|             else if ((m.is_eq(fml, t1, t2) && m.is_bool(t1)) || m.is_iff(fml, t1, t2)) { | ||||
|                 expr_ref tt1(m), tt2(m), ntt1(m), ntt2(m), nt1(m), nt2(m); | ||||
|                 pull_quantifier(t1, qt, vars, tt1); | ||||
|                 pull_quantifier(t2, qt, vars, tt2); | ||||
|                 nt1 = m.mk_not(t1); | ||||
|                 nt2 = m.mk_not(t2); | ||||
|                 pull_quantifier(nt1, qt, vars, ntt1); | ||||
|                 pull_quantifier(nt2, qt, vars, ntt2); | ||||
|                 result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(ntt2, tt1)); | ||||
|             } | ||||
|             else { | ||||
|                 // the formula contains a quantifier, but it is "inaccessible"
 | ||||
|  |  | |||
|  | @ -578,6 +578,16 @@ struct th_rewriter_cfg : public default_rewriter_cfg { | |||
|         return st; | ||||
|     } | ||||
| 
 | ||||
|     expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args) { | ||||
|         expr_ref result(m()); | ||||
|         proof_ref pr(m()); | ||||
|         if (BR_FAILED == reduce_app(f, num_args, args, result, pr)) { | ||||
|             result = m().mk_app(f, num_args, args); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     bool reduce_quantifier(quantifier * old_q,  | ||||
|                            expr * new_body,  | ||||
|                            expr * const * new_patterns,  | ||||
|  | @ -695,6 +705,9 @@ struct th_rewriter::imp : public rewriter_tpl<th_rewriter_cfg> { | |||
|         rewriter_tpl<th_rewriter_cfg>(m, m.proofs_enabled(), m_cfg), | ||||
|         m_cfg(m, p) { | ||||
|     } | ||||
|     expr_ref mk_app(func_decl* f, unsigned sz, expr* const* args) { | ||||
|         return m_cfg.mk_app(f, sz, args); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| th_rewriter::th_rewriter(ast_manager & m, params_ref const & p): | ||||
|  | @ -776,3 +789,7 @@ void th_rewriter::reset_used_dependencies() { | |||
|         m_imp->cfg().m_used_dependencies = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args) { | ||||
|     return m_imp->mk_app(f, num_args, args); | ||||
| } | ||||
|  |  | |||
|  | @ -45,6 +45,8 @@ public: | |||
|     void operator()(expr * t, expr_ref & result, proof_ref & result_pr); | ||||
|     void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result); | ||||
| 
 | ||||
|     expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args); | ||||
| 
 | ||||
|     void cleanup(); | ||||
|     void reset(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -303,8 +303,8 @@ public: | |||
|             goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores()); | ||||
|             assert_exprs_from(ctx, *g); | ||||
| 
 | ||||
|             unsigned timeout   = p.get_uint("timeout", UINT_MAX); | ||||
|             unsigned rlimit  =   p.get_uint("rlimit", 0); | ||||
|             unsigned timeout   = p.get_uint("timeout", ctx.params().m_timeout); | ||||
|             unsigned rlimit  =   p.get_uint("rlimit", ctx.params().m_rlimit); | ||||
| 
 | ||||
|             goal_ref_buffer     result_goals; | ||||
|             model_converter_ref mc; | ||||
|  |  | |||
|  | @ -539,7 +539,6 @@ namespace algebraic_numbers { | |||
|         } | ||||
| 
 | ||||
|         bool factor(scoped_upoly const & up, factors & r) { | ||||
|             // std::cout << "factor: "; upm().display(std::cout, up); std::cout << std::endl;
 | ||||
|             if (m_factor) { | ||||
|                 return upm().factor(up, r, m_factor_params); | ||||
|             } | ||||
|  | @ -547,7 +546,7 @@ namespace algebraic_numbers { | |||
|                 scoped_upoly & up_sqf = m_isolate_tmp3; | ||||
|                 up_sqf.reset(); | ||||
|                 upm().square_free(up.size(), up.c_ptr(), up_sqf); | ||||
|                 TRACE("anum_bug", upm().display(tout, up_sqf.size(), up_sqf.c_ptr()); tout << "\n";); | ||||
|                 TRACE("algebraic", upm().display(tout, up_sqf.size(), up_sqf.c_ptr()); tout << "\n";); | ||||
|                 r.push_back(up_sqf, 1); | ||||
|                 return false; | ||||
|             } | ||||
|  | @ -566,6 +565,7 @@ namespace algebraic_numbers { | |||
|         } | ||||
| 
 | ||||
|         void isolate_roots(scoped_upoly const & up, numeral_vector & roots) { | ||||
|             TRACE("algebraic", upm().display(tout, up); tout << "\n";); | ||||
|             if (up.empty()) | ||||
|                 return; // ignore the zero polynomial
 | ||||
|             factors & fs = m_isolate_factors; | ||||
|  | @ -586,6 +586,7 @@ namespace algebraic_numbers { | |||
|                 upolynomial::numeral_vector const & f = fs[i]; | ||||
|                 // polynomial f contains the non zero roots
 | ||||
|                 unsigned d = upm().degree(f); | ||||
|                 TRACE("algebraic", tout << "factor " << i << " degree: " << d << "\n";); | ||||
|                 if (d == 0) | ||||
|                     continue; // found all roots of f
 | ||||
|                 scoped_mpq r(qm()); | ||||
|  | @ -601,8 +602,9 @@ namespace algebraic_numbers { | |||
|                 } | ||||
|                 SASSERT(m_isolate_roots.empty() && m_isolate_lowers.empty() && m_isolate_uppers.empty()); | ||||
|                 upm().sqf_isolate_roots(f.size(), f.c_ptr(), bqm(), m_isolate_roots, m_isolate_lowers, m_isolate_uppers); | ||||
|                 // collect rational/basic roots
 | ||||
|                 // collect rational/basic roots                
 | ||||
|                 unsigned sz = m_isolate_roots.size(); | ||||
|                 TRACE("algebraic", tout << "isolated roots: " << sz << "\n";); | ||||
|                 for (unsigned i = 0; i < sz; i++) { | ||||
|                     to_mpq(qm(), m_isolate_roots[i], r); | ||||
|                     roots.push_back(numeral(mk_basic_cell(r))); | ||||
|  |  | |||
|  | @ -4,6 +4,5 @@ def_module_params('model', | |||
|                           ('v1', BOOL, False, 'use Z3 version 1.x pretty printer'), | ||||
|                           ('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'), | ||||
|                           ('compact', BOOL, False, 'try to compact function graph (i.e., function interpretations that are lookup tables)'), | ||||
|                           ('new_eval', BOOL, True, 'use new evaluator (temporary parameter for testing)'), | ||||
|                           )) | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,8 +55,7 @@ namespace datalog { | |||
|           m_args(m), | ||||
|           m_hnf(m), | ||||
|           m_qe(m), | ||||
|           m_cfg(m), | ||||
|           m_rwr(m, false, m_cfg), | ||||
|           m_rwr(m), | ||||
|           m_ufproc(m) {} | ||||
| 
 | ||||
|     void rule_manager::inc_ref(rule * r) { | ||||
|  | @ -76,28 +75,8 @@ namespace datalog { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     rule_manager::remove_label_cfg::~remove_label_cfg() {} | ||||
| 
 | ||||
|     br_status rule_manager::remove_label_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,  | ||||
|                                                          proof_ref & result_pr) | ||||
|     { | ||||
|         if (is_decl_of(f, m_label_fid, OP_LABEL)) { | ||||
|             SASSERT(num == 1); | ||||
|             result = args[0]; | ||||
|             return BR_DONE; | ||||
|         } | ||||
|         return BR_FAILED; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) { | ||||
|         expr_ref tmp(m); | ||||
|         m_rwr(fml, tmp); | ||||
|         if (pr && fml != tmp) { | ||||
|              | ||||
|             pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp)); | ||||
|         } | ||||
|         fml = tmp; | ||||
|         m_rwr.remove_labels(fml, pr); | ||||
|     } | ||||
| 
 | ||||
|     var_idx_set& rule_manager::collect_vars(expr* e) { | ||||
|  | @ -1092,5 +1071,4 @@ namespace datalog { | |||
|      | ||||
| }; | ||||
| 
 | ||||
| template class rewriter_tpl<datalog::rule_manager::remove_label_cfg>; | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ Revision History: | |||
| #include"qe_lite.h" | ||||
| #include"var_subst.h" | ||||
| #include"datatype_decl_plugin.h" | ||||
| #include"label_rewriter.h" | ||||
| 
 | ||||
| namespace datalog { | ||||
| 
 | ||||
|  | @ -102,16 +103,6 @@ namespace datalog { | |||
|     */ | ||||
|     class rule_manager | ||||
|     { | ||||
|         class remove_label_cfg : public default_rewriter_cfg { | ||||
|             family_id m_label_fid; | ||||
|         public:         | ||||
|             remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {} | ||||
|             virtual ~remove_label_cfg(); | ||||
|              | ||||
|             br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,  | ||||
|                                  proof_ref & result_pr); | ||||
|         }; | ||||
|      | ||||
|         ast_manager&         m; | ||||
|         context&             m_ctx; | ||||
|         rule_counter         m_counter; | ||||
|  | @ -124,8 +115,7 @@ namespace datalog { | |||
|         svector<bool>        m_neg; | ||||
|         hnf                  m_hnf; | ||||
|         qe_lite              m_qe; | ||||
|         remove_label_cfg               m_cfg; | ||||
|         rewriter_tpl<remove_label_cfg> m_rwr; | ||||
|         label_rewriter       m_rwr; | ||||
|         mutable uninterpreted_function_finder_proc m_ufproc; | ||||
|         mutable quantifier_finder_proc m_qproc; | ||||
|         mutable expr_sparse_mark       m_visited; | ||||
|  |  | |||
|  | @ -29,7 +29,6 @@ Revision History: | |||
| #include"ast_counter.h" | ||||
| #include"statistics.h" | ||||
| #include"lbool.h" | ||||
| #include"qe_util.h" | ||||
| 
 | ||||
| namespace datalog { | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ Revision History: | |||
| #include "pdr_closure.h" | ||||
| #include "pdr_context.h" | ||||
| #include "expr_safe_replace.h" | ||||
| #include "ast_util.h" | ||||
| 
 | ||||
| namespace pdr { | ||||
| 
 | ||||
|  | @ -147,7 +148,7 @@ namespace pdr { | |||
|         for (unsigned i = 0; i < fmls.size(); ++i) { | ||||
|             fmls[i] = close_fml(fmls[i].get());             | ||||
|         } | ||||
|         return qe::mk_and(fmls); | ||||
|         return expr_ref(mk_and(fmls), m); | ||||
|     } | ||||
| 
 | ||||
|     expr_ref closure::relax(unsigned i, expr* fml) { | ||||
|  | @ -169,7 +170,7 @@ namespace pdr { | |||
|         for (unsigned i = 0; i < As.size(); ++i) { | ||||
|             fmls.push_back(relax(i, As[i])); | ||||
|         } | ||||
|         B = qe::mk_and(fmls); | ||||
|         B = mk_and(fmls); | ||||
|         return B; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,7 +45,6 @@ Notes: | |||
| #include "smt_value_sort.h" | ||||
| #include "proof_utils.h" | ||||
| #include "dl_boogie_proof.h" | ||||
| #include "qe_util.h" | ||||
| #include "scoped_proof.h" | ||||
| #include "blast_term_ite_tactic.h" | ||||
| #include "model_implicant.h" | ||||
|  |  | |||
|  | @ -201,7 +201,7 @@ namespace pdr { | |||
|                 lits.push_back(extract_consequence(lo, hi)); | ||||
|                 lo = hi; | ||||
|             } | ||||
|             res = qe::mk_or(lits); | ||||
|             res = mk_or(lits); | ||||
|             IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } }); | ||||
| #endif | ||||
|         } | ||||
|  | @ -415,6 +415,7 @@ namespace pdr { | |||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     class collect_pure_proc { | ||||
|  |  | |||
|  | @ -117,7 +117,7 @@ namespace pdr { | |||
|     void core_farkas_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { | ||||
|         ast_manager& m  = n.pt().get_manager(); | ||||
|         if (core.empty()) return; | ||||
|         expr_ref A(m), B(qe::mk_and(core)), C(m); | ||||
|         expr_ref A(m), B(mk_and(core)), C(m); | ||||
|         expr_ref_vector Bs(m); | ||||
|         flatten_or(B, Bs); | ||||
|         A = n.pt().get_propagation_formula(m_ctx.get_pred_transformers(), n.level()); | ||||
|  | @ -129,13 +129,13 @@ namespace pdr { | |||
|             if (m_farkas_learner.get_lemma_guesses(A, B, lemmas)) { | ||||
|                 TRACE("pdr",  | ||||
|                       tout << "Old core:\n" << mk_pp(B, m) << "\n"; | ||||
|                       tout << "New core:\n" << mk_pp(qe::mk_and(lemmas), m) << "\n";);             | ||||
|                 Bs[i] = qe::mk_and(lemmas); | ||||
|                       tout << "New core:\n" << mk_and(lemmas) << "\n";);             | ||||
|                 Bs[i] = mk_and(lemmas); | ||||
|                 change = true; | ||||
|             } | ||||
|         } | ||||
|         if (change) { | ||||
|             C = qe::mk_or(Bs); | ||||
|             C = mk_or(Bs); | ||||
|             TRACE("pdr", tout << "prop:\n" << mk_pp(A,m) << "\ngen:" << mk_pp(B, m) << "\nto: " << mk_pp(C, m) << "\n";); | ||||
|             core.reset(); | ||||
|             flatten_and(C, core);     | ||||
|  | @ -186,7 +186,7 @@ namespace pdr { | |||
|         }         | ||||
|         closure cl(n.pt(), m_is_closure); | ||||
| 
 | ||||
|         expr_ref fml1 = qe::mk_and(core);         | ||||
|         expr_ref fml1 = mk_and(core);         | ||||
|         expr_ref fml2 = n.pt().get_formulas(n.level(), false); | ||||
|         fml1_2.push_back(fml1); | ||||
|         fml1_2.push_back(0); | ||||
|  | @ -205,7 +205,7 @@ namespace pdr { | |||
|             if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) { | ||||
|                 new_cores.push_back(std::make_pair(conv2, uses_level1)); | ||||
|                 change = true; | ||||
|                 expr_ref state1 = qe::mk_and(conv2); | ||||
|                 expr_ref state1 = mk_and(conv2); | ||||
|                 TRACE("pdr",  | ||||
|                       tout << mk_pp(state, m) << "\n"; | ||||
|                       tout << "Generalized to:\n" << mk_pp(state1, m) << "\n";); | ||||
|  | @ -593,7 +593,7 @@ namespace pdr { | |||
|             for (unsigned i = ut_size; i < t_size; i++) { | ||||
|                 conj.push_back(rule.get_tail(i)); | ||||
|             }          | ||||
|             result = qe::mk_and(conj); | ||||
|             result = mk_and(conj); | ||||
|             if (!sub.empty()) { | ||||
|                 expr_ref tmp = result; | ||||
|                 var_subst(m, false)(tmp, sub.size(), sub.c_ptr(), result); | ||||
|  | @ -685,7 +685,7 @@ namespace pdr { | |||
|             for (unsigned i = 0; i < rules.size(); ++i) { | ||||
|                 fmls.push_back(m.mk_not(mk_transition_rule(reps, level, *rules[i])));            | ||||
|             } | ||||
|             fml = qe::mk_and(fmls); | ||||
|             fml = mk_and(fmls); | ||||
|             TRACE("pdr", tout << mk_pp(fml, m) << "\n";); | ||||
|             return fml; | ||||
|         } | ||||
|  | @ -741,7 +741,7 @@ namespace pdr { | |||
|                 }                 | ||||
|             } | ||||
| 
 | ||||
|             expr_ref result = qe::mk_and(conjs); | ||||
|             expr_ref result = mk_and(conjs); | ||||
|             TRACE("pdr", tout << mk_pp(result, m) << "\n";); | ||||
|             return result; | ||||
|         } | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ Copyright (c) 2015 Microsoft Corporation | |||
| 
 | ||||
| #include "check_relation.h" | ||||
| #include "dl_relation_manager.h" | ||||
| #include "qe_util.h" | ||||
| #include "ast_util.h" | ||||
| #include "smt_kernel.h" | ||||
| #include <typeinfo> | ||||
|  |  | |||
|  | @ -23,7 +23,6 @@ Notes: | |||
| --*/ | ||||
| #include "udoc_relation.h" | ||||
| #include "dl_relation_manager.h" | ||||
| #include "qe_util.h" | ||||
| #include "ast_util.h" | ||||
| #include "smt_kernel.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,6 +39,17 @@ namespace nlsat { | |||
|             m_values.swap(other.m_values); | ||||
|             m_assigned.swap(other.m_assigned); | ||||
|         } | ||||
|         void copy(assignment const& other) { | ||||
|             m_assigned.reset(); | ||||
|             m_assigned.append(other.m_assigned); | ||||
|             m_values.reserve(m_assigned.size(), anum()); | ||||
|             for (unsigned i = 0; i < m_assigned.size(); ++i) { | ||||
|                 if (is_assigned(i)) { | ||||
|                     am().set(m_values[i], other.value(i)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void set_core(var x, anum & v) { | ||||
|             m_values.reserve(x+1, anum()); | ||||
|             m_assigned.reserve(x+1, false);  | ||||
|  | @ -52,11 +63,26 @@ namespace nlsat { | |||
|             am().set(m_values[x], v);  | ||||
|         } | ||||
|         void reset(var x) { if (x < m_assigned.size()) m_assigned[x] = false; } | ||||
|         void reset() { m_assigned.reset(); } | ||||
|         bool is_assigned(var x) const { return m_assigned.get(x, false); } | ||||
|         anum const & value(var x) const { return m_values[x]; } | ||||
|         virtual anum_manager & m() const { return am(); } | ||||
|         virtual bool contains(var x) const { return is_assigned(x); } | ||||
|         virtual anum const & operator()(var x) const { SASSERT(is_assigned(x)); return value(x); } | ||||
|         void swap(var x, var y) { | ||||
|             SASSERT(x < m_values.size() && y < m_values.size()); | ||||
|             std::swap(m_assigned[x], m_assigned[y]); | ||||
|             std::swap(m_values[x], m_values[y]); | ||||
|         } | ||||
|         void display(std::ostream& out) const { | ||||
|             for (unsigned i = 0; i < m_assigned.size(); ++i) { | ||||
|                 if (m_assigned[i]) { | ||||
|                     out << "x" << i << " := "; | ||||
|                     m_values.m().display(out, m_values[i]); | ||||
|                     out << "\n"; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|  |  | |||
|  | @ -18,10 +18,12 @@ Revision History: | |||
| 
 | ||||
| --*/ | ||||
| #include"nlsat_evaluator.h" | ||||
| #include"nlsat_solver.h" | ||||
| 
 | ||||
| namespace nlsat { | ||||
| 
 | ||||
|     struct evaluator::imp { | ||||
|         solver&                  m_solver; | ||||
|         assignment const &       m_assignment; | ||||
|         pmanager &               m_pm; | ||||
|         small_object_allocator & m_allocator; | ||||
|  | @ -357,7 +359,8 @@ namespace nlsat { | |||
| 
 | ||||
|         sign_table m_sign_table_tmp; | ||||
| 
 | ||||
|         imp(assignment const & x2v, pmanager & pm, small_object_allocator & allocator): | ||||
|         imp(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator): | ||||
|             m_solver(s), | ||||
|             m_assignment(x2v), | ||||
|             m_pm(pm), | ||||
|             m_allocator(allocator), | ||||
|  | @ -420,10 +423,25 @@ namespace nlsat { | |||
|             scoped_anum_vector & roots = m_tmp_values; | ||||
|             roots.reset(); | ||||
|             m_am.isolate_roots(polynomial_ref(a->p(), m_pm), undef_var_assignment(m_assignment, a->x()), roots); | ||||
|             TRACE("nlsat", | ||||
|                   m_solver.display(tout << (neg?"!":""), *a); tout << "\n"; | ||||
|                   if (roots.empty()) { | ||||
|                       tout << "No roots\n"; | ||||
|                   } | ||||
|                   else { | ||||
|                       tout << "Roots for "; | ||||
|                       for (unsigned i = 0; i < roots.size(); ++i) { | ||||
|                           m_am.display_interval(tout, roots[i]); tout << " ";  | ||||
|                       } | ||||
|                       tout << "\n"; | ||||
|                   } | ||||
|                   m_assignment.display(tout); | ||||
|                   ); | ||||
|             SASSERT(a->i() > 0); | ||||
|             if (a->i() > roots.size()) | ||||
|                 return false; // p does have sufficient roots
 | ||||
|             int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]); | ||||
|             if (a->i() > roots.size()) { | ||||
|                 return neg; | ||||
|             } | ||||
|             int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]);             | ||||
|             return satisfied(sign, k, neg); | ||||
|         } | ||||
|          | ||||
|  | @ -649,8 +667,8 @@ namespace nlsat { | |||
|         } | ||||
|     }; | ||||
|      | ||||
|     evaluator::evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator) { | ||||
|         m_imp = alloc(imp, x2v, pm, allocator); | ||||
|     evaluator::evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator) { | ||||
|         m_imp = alloc(imp, s, x2v, pm, allocator); | ||||
|     } | ||||
| 
 | ||||
|     evaluator::~evaluator() { | ||||
|  |  | |||
|  | @ -26,11 +26,13 @@ Revision History: | |||
| 
 | ||||
| namespace nlsat { | ||||
| 
 | ||||
|     class solver; | ||||
| 
 | ||||
|     class evaluator { | ||||
|         struct imp; | ||||
|         imp *  m_imp; | ||||
|     public: | ||||
|         evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator); | ||||
|         evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator); | ||||
|         ~evaluator(); | ||||
| 
 | ||||
|         interval_set_manager & ism() const; | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ namespace nlsat { | |||
|         polynomial::cache &     m_cache; | ||||
|         pmanager &              m_pm; | ||||
|         polynomial_ref_vector   m_ps; | ||||
|         polynomial_ref_vector   m_ps2; | ||||
|         polynomial_ref_vector   m_psc_tmp; | ||||
|         polynomial_ref_vector   m_factors; | ||||
|         scoped_anum_vector      m_roots_tmp; | ||||
|  | @ -43,6 +44,7 @@ namespace nlsat { | |||
|         bool                    m_full_dimensional; | ||||
|         bool                    m_minimize_cores; | ||||
|         bool                    m_factor; | ||||
|         bool                    m_signed_project; | ||||
| 
 | ||||
|         struct todo_set { | ||||
|             polynomial::cache  &    m_cache; | ||||
|  | @ -137,6 +139,7 @@ namespace nlsat { | |||
|             m_cache(u),  | ||||
|             m_pm(u.pm()), | ||||
|             m_ps(m_pm), | ||||
|             m_ps2(m_pm), | ||||
|             m_psc_tmp(m_pm), | ||||
|             m_factors(m_pm), | ||||
|             m_roots_tmp(m_am), | ||||
|  | @ -148,6 +151,7 @@ namespace nlsat { | |||
|             m_simplify_cores   = false; | ||||
|             m_full_dimensional = false; | ||||
|             m_minimize_cores   = false; | ||||
|             m_signed_project   = false; | ||||
|         } | ||||
|          | ||||
|         ~imp() { | ||||
|  | @ -202,7 +206,7 @@ namespace nlsat { | |||
|         void reset_already_added() { | ||||
|             SASSERT(m_result != 0); | ||||
|             unsigned sz = m_result->size(); | ||||
|             for (unsigned i = 0; i < sz; i++) | ||||
|             for (unsigned i = 0; i < sz; i++)  | ||||
|                 m_already_added_literal[(*m_result)[i].index()] = false; | ||||
|         } | ||||
| 
 | ||||
|  | @ -212,7 +216,7 @@ namespace nlsat { | |||
|            max_var(p) must be assigned in the current interpretation. | ||||
|         */ | ||||
|         int sign(polynomial_ref const & p) { | ||||
|             TRACE("nlsat_explain", tout << "p: " << p << "\n";); | ||||
|             TRACE("nlsat_explain", tout << "p: " << p << " var: " << max_var(p) << "\n";); | ||||
|             SASSERT(max_var(p) == null_var || m_assignment.is_assigned(max_var(p))); | ||||
|             return m_am.eval_sign_at(p, m_assignment); | ||||
|         } | ||||
|  | @ -697,39 +701,163 @@ namespace nlsat { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void test_root_literal(atom::kind k, var y, unsigned i, poly * p, scoped_literal_vector& result) { | ||||
|             m_result = &result; | ||||
|             add_root_literal(k, y, i, p); | ||||
|             reset_already_added(); | ||||
|             m_result = 0; | ||||
|         } | ||||
| 
 | ||||
|         void add_root_literal(atom::kind k, var y, unsigned i, poly * p) { | ||||
|             polynomial_ref pr(p, m_pm); | ||||
|             TRACE("nlsat_explain",  | ||||
|                   display(tout << "x" << y << " " << k << "[" << i << "](", pr); tout << ")\n";); | ||||
| 
 | ||||
|             if (!mk_linear_root(k, y, i, p) && | ||||
|                 //!mk_plinear_root(k, y, i, p) &&
 | ||||
|                 !mk_quadratic_root(k, y, i, p)&& | ||||
|                 true) {                 | ||||
|                 bool_var b = m_solver.mk_root_atom(k, y, i, p); | ||||
|                 literal l(b, true); | ||||
|                 TRACE("nlsat_explain", tout << "adding literal\n"; display(tout, l); tout << "\n";); | ||||
|                 add_literal(l); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|          * literal can be expressed using a linear ineq_atom | ||||
|          */ | ||||
|         bool mk_linear_root(atom::kind k, var y, unsigned i, poly * p) { | ||||
|             scoped_mpz c(m_pm.m()); | ||||
|             bool_var b; | ||||
|             bool     lsign = false; | ||||
|             if (m_pm.degree(p, y) == 1 && m_pm.const_coeff(p, y, 1, c)) { | ||||
|                 SASSERT(!m_pm.m().is_zero(c)); | ||||
|                 // literal can be expressed using a linear ineq_atom
 | ||||
|                 polynomial_ref p_prime(m_pm); | ||||
|                 p_prime = p; | ||||
|                 if (m_pm.m().is_neg(c))  | ||||
|                     p_prime = neg(p_prime); | ||||
|                 p = p_prime.get(); | ||||
|                 switch (k) { | ||||
|                 case atom::ROOT_EQ: k = atom::EQ; lsign = false; break; | ||||
|                 case atom::ROOT_LT: k = atom::LT; lsign = false; break; | ||||
|                 case atom::ROOT_GT: k = atom::GT; lsign = false; break; | ||||
|                 case atom::ROOT_LE: k = atom::GT; lsign = true; break; | ||||
|                 case atom::ROOT_GE: k = atom::LT; lsign = true; break; | ||||
|                 default: | ||||
|                     UNREACHABLE(); | ||||
|                     break; | ||||
|                 } | ||||
|                 bool is_even = false; | ||||
|                 b = m_solver.mk_ineq_atom(k, 1, &p, &is_even); | ||||
|                 mk_linear_root(k, y, i, p, m_pm.m().is_neg(c)); | ||||
|                 return true; | ||||
|             } | ||||
|             else { | ||||
|                 b   = m_solver.mk_root_atom(k, y, i, p); | ||||
|                 lsign = false; | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         /**
 | ||||
|            Create pseudo-linear root depending on the sign of the coefficient to y. | ||||
|          */ | ||||
|         bool mk_plinear_root(atom::kind k, var y, unsigned i, poly * p) { | ||||
|             if (m_pm.degree(p, y) != 1) { | ||||
|                 return false; | ||||
|             } | ||||
|             lsign = !lsign; // adding as an assumption
 | ||||
|             literal l(b, lsign); | ||||
|             TRACE("nlsat_explain", tout << "adding literal\n"; display(tout, l); tout << "\n";); | ||||
|             add_literal(l); | ||||
|             polynomial_ref c(m_pm); | ||||
|             c = m_pm.coeff(p, y, 1); | ||||
|             int s = sign(c); | ||||
|             if (s == 0) { | ||||
|                 return false; | ||||
|             } | ||||
|             ensure_sign(c); | ||||
|             mk_linear_root(k, y, i, p, s < 0);                 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|            Encode root conditions for quadratic polynomials. | ||||
|             | ||||
|            Basically implements Thom's theorem. The roots are characterized by the sign of polynomials and their derivatives. | ||||
| 
 | ||||
|            b^2 - 4ac = 0: | ||||
|               - there is only one root, which is -b/2a. | ||||
|               - relation to root is a function of the sign of  | ||||
|               - 2ax + b | ||||
|            b^2 - 4ac > 0: | ||||
|               - assert i == 1 or i == 2 | ||||
|               - relation to root is a function of the signs of: | ||||
|                 - 2ax + b | ||||
|                 - ax^2 + bx + c | ||||
|          */ | ||||
| 
 | ||||
|         bool mk_quadratic_root(atom::kind k, var y, unsigned i, poly * p) { | ||||
|             if (m_pm.degree(p, y) != 2) { | ||||
|                 return false; | ||||
|             } | ||||
|             if (i != 1 && i != 2) { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             SASSERT(m_assignment.is_assigned(y)); | ||||
|             polynomial_ref A(m_pm), B(m_pm), C(m_pm), q(m_pm), p_diff(m_pm), yy(m_pm); | ||||
|             A = m_pm.coeff(p, y, 2); | ||||
|             B = m_pm.coeff(p, y, 1); | ||||
|             C = m_pm.coeff(p, y, 0); | ||||
|             // TBD throttle based on degree of q?
 | ||||
|             q = (B*B) - (4*A*C); | ||||
|             yy = m_pm.mk_polynomial(y); | ||||
|             p_diff = 2*A*yy + B; | ||||
|             p_diff = m_pm.normalize(p_diff); | ||||
|             int sq = ensure_sign(q);  | ||||
|             if (sq < 0) { | ||||
|                 return false; | ||||
|             } | ||||
|             int sa = ensure_sign(A); | ||||
|             if (sa == 0) { | ||||
|                 q = B*yy + C; | ||||
|                 return mk_plinear_root(k, y, i, q); | ||||
|             }  | ||||
|             ensure_sign(p_diff); | ||||
|             if (sq > 0) { | ||||
|                 polynomial_ref pr(p, m_pm); | ||||
|                 ensure_sign(pr); | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         int ensure_sign(polynomial_ref & p) { | ||||
| #if 0 | ||||
|             polynomial_ref f(m_pm); | ||||
|             factor(p, m_factors); | ||||
|             m_is_even.reset(); | ||||
|             unsigned num_factors = m_factors.size(); | ||||
|             int s = 1; | ||||
|             for (unsigned i = 0; i < num_factors; i++) { | ||||
|                 f = m_factors.get(i); | ||||
|                 s *= sign(f); | ||||
|                 m_is_even.push_back(false); | ||||
|             }  | ||||
|             if (num_factors > 0) { | ||||
|                 atom::kind k = atom::EQ; | ||||
|                 if (s == 0) k = atom::EQ; | ||||
|                 if (s < 0)  k = atom::LT; | ||||
|                 if (s > 0)  k = atom::GT; | ||||
|                 bool_var b = m_solver.mk_ineq_atom(k, num_factors, m_factors.c_ptr(), m_is_even.c_ptr()); | ||||
|                 add_literal(literal(b, true)); | ||||
|             } | ||||
|             return s; | ||||
| #else | ||||
|             int s = sign(p); | ||||
|             if (!is_const(p)) { | ||||
|                 add_simple_assumption(s == 0 ? atom::EQ : (s < 0 ? atom::LT : atom::GT), p); | ||||
|             } | ||||
|             return s; | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|            Auxiliary function to linear roots. | ||||
|          */ | ||||
|         void mk_linear_root(atom::kind k, var y, unsigned i, poly * p, bool mk_neg) { | ||||
|             polynomial_ref p_prime(m_pm); | ||||
|             p_prime = p; | ||||
|             bool lsign = false; | ||||
|             if (mk_neg) | ||||
|                 p_prime = neg(p_prime); | ||||
|             p = p_prime.get(); | ||||
|             switch (k) { | ||||
|             case atom::ROOT_EQ: k = atom::EQ; lsign = false; break; | ||||
|             case atom::ROOT_LT: k = atom::LT; lsign = false; break; | ||||
|             case atom::ROOT_GT: k = atom::GT; lsign = false; break; | ||||
|             case atom::ROOT_LE: k = atom::GT; lsign = true; break; | ||||
|             case atom::ROOT_GE: k = atom::LT; lsign = true; break; | ||||
|             default: | ||||
|                 UNREACHABLE(); | ||||
|                 break; | ||||
|             } | ||||
|             add_simple_assumption(k, p, lsign); | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|  | @ -1332,10 +1460,333 @@ namespace nlsat { | |||
|             TRACE("nlsat_explain", tout << "[explain] result\n"; display(tout, result);); | ||||
|             CASSERT("nlsat", check_already_added()); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         void project(var x, unsigned num, literal const * ls, scoped_literal_vector & result) { | ||||
|             m_result = &result; | ||||
|             svector<literal> lits; | ||||
|             TRACE("nlsat", tout << "project x" << x << "\n"; m_solver.display(tout);); | ||||
|                    | ||||
|             DEBUG_CODE( | ||||
|                 for (unsigned i = 0; i < num; ++i) { | ||||
|                     SASSERT(m_solver.value(ls[i]) == l_true); | ||||
|                     atom* a = m_atoms[ls[i].var()]; | ||||
|                     SASSERT(!a || m_evaluator.eval(a, ls[i].sign())); | ||||
|                 }); | ||||
|             split_literals(x, num, ls, lits); | ||||
|             collect_polys(lits.size(), lits.c_ptr(), m_ps); | ||||
|             var mx_var = max_var(m_ps); | ||||
|             if (!m_ps.empty()) {                 | ||||
|                 svector<var> renaming; | ||||
|                 if (x != mx_var) { | ||||
|                     for (var i = 0; i < m_solver.num_vars(); ++i) { | ||||
|                         renaming.push_back(i); | ||||
|                     } | ||||
|                     std::swap(renaming[x], renaming[mx_var]); | ||||
|                     m_solver.reorder(renaming.size(), renaming.c_ptr()); | ||||
|                     TRACE("qe", tout << "x: " << x << " max: " << mx_var << " num_vars: " << m_solver.num_vars() << "\n"; | ||||
|                           m_solver.display(tout);); | ||||
|                 } | ||||
|                 elim_vanishing(m_ps); | ||||
|                 if (m_signed_project) { | ||||
|                     signed_project(m_ps, mx_var); | ||||
|                 } | ||||
|                 else { | ||||
|                     project(m_ps, mx_var); | ||||
|                 } | ||||
|                 reset_already_added(); | ||||
|                 m_result = 0; | ||||
|                 if (x != mx_var) { | ||||
|                     m_solver.restore_order(); | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|                 reset_already_added(); | ||||
|                 m_result = 0; | ||||
|             } | ||||
|             for (unsigned i = 0; i < result.size(); ++i) { | ||||
|                 result.set(i, ~result[i]); | ||||
|             } | ||||
|             DEBUG_CODE( | ||||
|                 for (unsigned i = 0; i < result.size(); ++i) { | ||||
|                     SASSERT(l_true == m_solver.value(result[i])); | ||||
|                 }); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         void split_literals(var x, unsigned n, literal const* ls, svector<literal>& lits) { | ||||
|             var_vector vs; | ||||
|             for (unsigned i = 0; i < n; ++i) {                   | ||||
|                 vs.reset(); | ||||
|                 m_solver.vars(ls[i], vs); | ||||
|                 if (vs.contains(x)) { | ||||
|                     lits.push_back(ls[i]); | ||||
|                 } | ||||
|                 else { | ||||
|                     add_literal(~ls[i]); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|            Signed projection.  | ||||
| 
 | ||||
|            Assumptions: | ||||
|            - any variable in ps is at most x. | ||||
|            - root expressions are satisfied (positive literals) | ||||
|             | ||||
|            Effect: | ||||
|            - if x not in p, then | ||||
|               - if sign(p) < 0:   p < 0 | ||||
|               - if sign(p) = 0:   p = 0 | ||||
|               - if sign(p) > 0:   p > 0 | ||||
|            else: | ||||
|            - let roots_j be the roots of p_j or roots_j[i]  | ||||
|            - let L = { roots_j[i] | M(roots_j[i]) < M(x) } | ||||
|            - let U = { roots_j[i] | M(roots_j[i]) > M(x) } | ||||
|            - let E = { roots_j[i] | M(roots_j[i]) = M(x) } | ||||
|            - let glb in L, s.t. forall l in L . M(glb) >= M(l) | ||||
|            - let lub in U, s.t. forall u in U . M(lub) <= M(u) | ||||
|            - if root in E, then  | ||||
|               - add E x . x = root & x > lb  for lb in L | ||||
|               - add E x . x = root & x < ub  for ub in U | ||||
|               - add E x . x = root & x = root2  for root2 in E \ { root } | ||||
|            - else  | ||||
|              - assume |L| <= |U| (other case is symmetric) | ||||
|              - add E x . lb <= x & x <= glb for lb in L | ||||
|              - add E x . x = glb & x < ub  for ub in U | ||||
|          */ | ||||
| 
 | ||||
| 
 | ||||
|         void signed_project(polynomial_ref_vector& ps, var x) { | ||||
|              | ||||
|             TRACE("nlsat_explain", tout << "Signed projection\n";); | ||||
|             polynomial_ref p(m_pm); | ||||
|             unsigned eq_index = 0; | ||||
|             bool eq_valid = false; | ||||
|             unsigned eq_degree = 0; | ||||
|             for (unsigned i = 0; i < ps.size(); ++i) { | ||||
|                 p = ps.get(i); | ||||
|                 int s = sign(p); | ||||
|                 if (max_var(p) != x) { | ||||
|                     atom::kind k = (s == 0)?(atom::EQ):((s < 0)?(atom::LT):(atom::GT)); | ||||
|                     add_simple_assumption(k, p, false); | ||||
|                     ps[i] = ps.back(); | ||||
|                     ps.pop_back(); | ||||
|                     --i; | ||||
|                 } | ||||
|                 else if (s == 0) { | ||||
|                     if (!eq_valid || degree(p, x) < eq_degree) { | ||||
|                         eq_index = i; | ||||
|                         eq_valid = true; | ||||
|                         eq_degree = degree(p, x); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (ps.empty()) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (ps.size() == 1) { | ||||
|                 project_single(x, ps.get(0)); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // ax + b = 0, p(x) > 0 -> 
 | ||||
| 
 | ||||
|             if (eq_valid) { | ||||
|                 p = ps.get(eq_index); | ||||
|                 if (degree(p, x) == 1) { | ||||
|                     // ax + b = 0
 | ||||
|                     // let d be maximal degree of x in p.
 | ||||
|                     // p(x) -> a^d*p(-b/a), a
 | ||||
|                     // perform virtual substitution with equality.
 | ||||
|                     solve_eq(x, eq_index, ps); | ||||
|                 } | ||||
|                 else { | ||||
|                     project_pairs(x, eq_index, ps); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
|             unsigned num_lub = 0, num_glb = 0; | ||||
|             unsigned glb_index = 0, lub_index = 0; | ||||
|             scoped_anum lub(m_am), glb(m_am), x_val(m_am); | ||||
|             x_val = m_assignment.value(x); | ||||
|             for (unsigned i = 0; i < ps.size(); ++i) { | ||||
|                 p = ps.get(i); | ||||
|                 scoped_anum_vector & roots = m_roots_tmp; | ||||
|                 roots.reset(); | ||||
|                 m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots); | ||||
|                 bool glb_valid = false, lub_valid = false; | ||||
|                 for (unsigned j = 0; j < roots.size(); ++j) { | ||||
|                     int s = m_am.compare(x_val, roots[j]); | ||||
|                     SASSERT(s != 0); | ||||
|                     lub_valid |= s < 0; | ||||
|                     glb_valid |= s > 0; | ||||
| 
 | ||||
|                     if (s < 0 && m_am.lt(roots[j], lub)) { | ||||
|                         lub_index = i; | ||||
|                         m_am.set(lub, roots[j]); | ||||
|                     } | ||||
| 
 | ||||
|                     if (s > 0 && m_am.lt(glb, roots[j])) { | ||||
|                         glb_index = i; | ||||
|                         m_am.set(glb, roots[j]);                         | ||||
|                     } | ||||
|                 } | ||||
|                 if (glb_valid) { | ||||
|                     ++num_glb; | ||||
|                 } | ||||
|                 if (lub_valid) { | ||||
|                     ++num_lub; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (num_lub == 0) { | ||||
|                 project_plus_infinity(x, ps); | ||||
|                 return; | ||||
|             } | ||||
|                  | ||||
|             if (num_glb == 0) { | ||||
|                 project_minus_infinity(x, ps); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (num_lub <= num_glb) { | ||||
|                 glb_index = lub_index; | ||||
|             } | ||||
| 
 | ||||
|             project_pairs(x, glb_index, ps); | ||||
|         } | ||||
| 
 | ||||
|         void project_plus_infinity(var x, polynomial_ref_vector const& ps) { | ||||
|             polynomial_ref p(m_pm), lc(m_pm); | ||||
|             for (unsigned i = 0; i < ps.size(); ++i) { | ||||
|                 p = ps.get(i); | ||||
|                 unsigned d = degree(p, x); | ||||
|                 lc = m_pm.coeff(p, x, d); | ||||
|                 if (!is_const(lc)) {                     | ||||
|                     unsigned s = sign(p); | ||||
|                     SASSERT(s != 0); | ||||
|                     atom::kind k = (s > 0)?(atom::GT):(atom::LT); | ||||
|                     add_simple_assumption(k, lc); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void project_minus_infinity(var x, polynomial_ref_vector const& ps) { | ||||
|             polynomial_ref p(m_pm), lc(m_pm); | ||||
|             for (unsigned i = 0; i < ps.size(); ++i) { | ||||
|                 p = ps.get(i); | ||||
|                 unsigned d = degree(p, x); | ||||
|                 lc = m_pm.coeff(p, x, d); | ||||
|                 if (!is_const(lc)) { | ||||
|                     unsigned s = sign(p); | ||||
|                     SASSERT(s != 0); | ||||
|                     atom::kind k; | ||||
|                     if (s > 0) { | ||||
|                         k = (d % 2 == 0)?(atom::GT):(atom::LT); | ||||
|                     } | ||||
|                     else { | ||||
|                         k = (d % 2 == 0)?(atom::LT):(atom::GT); | ||||
|                     } | ||||
|                     add_simple_assumption(k, lc); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void project_pairs(var x, unsigned idx, polynomial_ref_vector const& ps) { | ||||
|             polynomial_ref p(m_pm); | ||||
|             p = ps.get(idx); | ||||
|             for (unsigned i = 0; i < ps.size(); ++i) { | ||||
|                 if (i != idx) { | ||||
|                     project_pair(x, ps.get(i), p); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void project_pair(var x, polynomial::polynomial* p1, polynomial::polynomial* p2) { | ||||
|             m_ps2.reset(); | ||||
|             m_ps2.push_back(p1); | ||||
|             m_ps2.push_back(p2); | ||||
|             project(m_ps2, x); | ||||
|         } | ||||
| 
 | ||||
|         void project_single(var x, polynomial::polynomial* p) { | ||||
|             m_ps2.reset(); | ||||
|             m_ps2.push_back(p); | ||||
|             project(m_ps2, x); | ||||
|         } | ||||
| 
 | ||||
|         void solve_eq(var x, unsigned idx, polynomial_ref_vector const& ps) { | ||||
|             polynomial_ref p(m_pm), A(m_pm), B(m_pm), C(m_pm), D(m_pm), E(m_pm), q(m_pm), r(m_pm); | ||||
|             polynomial_ref_vector qs(m_pm); | ||||
|             p = ps.get(idx); | ||||
|             SASSERT(degree(p, x) == 1); | ||||
|             A = m_pm.coeff(p, x, 1); | ||||
|             B = m_pm.coeff(p, x, 0); | ||||
|             B = neg(B); | ||||
|             TRACE("nlsat_explain", tout << "p: " << p << " A: " << A << " B: " << B << "\n";); | ||||
|             // x = B/A
 | ||||
|             for (unsigned i = 0; i < ps.size(); ++i) { | ||||
|                 if (i != idx) { | ||||
|                     q = ps.get(i); | ||||
|                     unsigned d = degree(q, x); | ||||
|                     D = m_pm.mk_const(rational(1)); | ||||
|                     E = D; | ||||
|                     r = m_pm.mk_zero(); | ||||
|                     for (unsigned j = 0; j <= d; ++j) {                        | ||||
|                         qs.push_back(D); | ||||
|                         D = D*A; | ||||
|                     } | ||||
|                     for (unsigned j = 0; j <= d; ++j) { | ||||
|                         // A^d*p0 + A^{d-1}*B*p1 + ... + B^j*A^{d-j}*pj + ... + B^d*p_d
 | ||||
|                         C = m_pm.coeff(q, x, j); | ||||
|                         if (!is_zero(C)) { | ||||
|                             D = qs.get(d-j); | ||||
|                             r = r + D*E*C; | ||||
|                         } | ||||
|                         E = E*B; | ||||
|                     } | ||||
|                     TRACE("nlsat_explain", tout << "q: " << q << " r: " << r << "\n";); | ||||
|                     ensure_sign(r); | ||||
|                 } | ||||
|                 else { | ||||
|                     ensure_sign(A); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         void maximize(var x, unsigned num, literal const * ls, scoped_anum& val, bool& unbounded) { | ||||
|             svector<literal> lits; | ||||
|             polynomial_ref p(m_pm); | ||||
|             split_literals(x, num, ls, lits); | ||||
|             collect_polys(lits.size(), lits.c_ptr(), m_ps); | ||||
|             unbounded = true; | ||||
|             scoped_anum x_val(m_am); | ||||
|             x_val = m_assignment.value(x); | ||||
|             for (unsigned i = 0; i < m_ps.size(); ++i) { | ||||
|                 p = m_ps.get(i); | ||||
|                 scoped_anum_vector & roots = m_roots_tmp; | ||||
|                 roots.reset(); | ||||
|                 m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots); | ||||
|                 for (unsigned j = 0; j < roots.size(); ++j) { | ||||
|                     int s = m_am.compare(x_val, roots[j]); | ||||
|                     if (s <= 0 && (unbounded || m_am.compare(roots[j], val) <= 0)) { | ||||
|                         unbounded = false; | ||||
|                         val = roots[j]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     explain::explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq, | ||||
|                      evaluator & ev) { | ||||
|     explain::explain(solver & s, assignment const & x2v, polynomial::cache & u,  | ||||
|                      atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev) { | ||||
|         m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1364,10 +1815,26 @@ namespace nlsat { | |||
|         m_imp->m_factor = f; | ||||
|     } | ||||
| 
 | ||||
|     void explain::set_signed_project(bool f) { | ||||
|         m_imp->m_signed_project = f; | ||||
|     } | ||||
| 
 | ||||
|     void explain::operator()(unsigned n, literal const * ls, scoped_literal_vector & result) { | ||||
|         (*m_imp)(n, ls, result); | ||||
|     } | ||||
| 
 | ||||
|     void explain::project(var x, unsigned n, literal const * ls, scoped_literal_vector & result) { | ||||
|         m_imp->project(x, n, ls, result); | ||||
|     } | ||||
| 
 | ||||
|     void explain::maximize(var x, unsigned n, literal const * ls, scoped_anum& val, bool& unbounded) { | ||||
|         m_imp->maximize(x, n, ls, val, unbounded); | ||||
|     } | ||||
| 
 | ||||
|     void explain::test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result) { | ||||
|         m_imp->test_root_literal(k, y, i, p, result); | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| #ifdef Z3DEBUG | ||||
|  | @ -1398,3 +1865,4 @@ void pp_lit(nlsat::explain::imp & ex, nlsat::literal l) { | |||
|     std::cout << std::endl; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,9 +22,11 @@ Revision History: | |||
| #include"nlsat_solver.h" | ||||
| #include"nlsat_scoped_literal_vector.h" | ||||
| #include"polynomial_cache.h" | ||||
| #include"algebraic_numbers.h" | ||||
| 
 | ||||
| namespace nlsat { | ||||
|     class evaluator; | ||||
| 
 | ||||
|      | ||||
|     class explain { | ||||
|     public: | ||||
|  | @ -32,8 +34,8 @@ namespace nlsat { | |||
|     private: | ||||
|         imp * m_imp; | ||||
|     public: | ||||
|         explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq, | ||||
|                 evaluator & ev); | ||||
|         explain(solver & s, assignment const & x2v, polynomial::cache & u,  | ||||
|                 atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev); | ||||
|         ~explain(); | ||||
| 
 | ||||
|         void reset(); | ||||
|  | @ -41,6 +43,7 @@ namespace nlsat { | |||
|         void set_full_dimensional(bool f); | ||||
|         void set_minimize_cores(bool f); | ||||
|         void set_factor(bool f); | ||||
|         void set_signed_project(bool f); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Given a set of literals ls[0], ... ls[n-1] s.t. | ||||
|  | @ -60,6 +63,48 @@ namespace nlsat { | |||
|                  - s_1, ..., s_m are false in the current interpretation | ||||
|         */ | ||||
|         void operator()(unsigned n, literal const * ls, scoped_literal_vector & result); | ||||
| 
 | ||||
|          | ||||
|         /**
 | ||||
|            \brief projection for a given variable. | ||||
| 
 | ||||
|              Given:    M |= l1[x] /\ ... /\ ln[x] | ||||
|             | ||||
|              Find:     M |= s1, ..., sm | ||||
| 
 | ||||
|              Such that:  |= ~s1 \/ ... \/ ~sm \/ E x. l1[x] /\ ... /\ ln[x] | ||||
| 
 | ||||
|            Contrast this with with the core-based projection above: | ||||
| 
 | ||||
|              Given:     M |= A x . l1[x] \/  ... \/ ln[x] | ||||
|             | ||||
|              Find:      M |= ~s1, ..., ~sm. | ||||
| 
 | ||||
|              Such that:   |= s1 \/ ... \/ sm \/ A x . l1[x] \/  ... \/ ln[x]            | ||||
| 
 | ||||
|            Claim: the two compute the same solutions if the projection operators are independent of the value of x. | ||||
|            Claim: A complete, convergent projection operator can be obtained from M in a way that is independent of x. | ||||
| 
 | ||||
|             | ||||
|          */ | ||||
|         void project(var x, unsigned n, literal const * ls, scoped_literal_vector & result); | ||||
| 
 | ||||
|         /**
 | ||||
|            Maximize the value of x (locally) under the current assignment to other variables and | ||||
|            while maintaining the assignment to the literals ls. | ||||
|            Set unbounded to 'true' if the value of x is unbounded. | ||||
| 
 | ||||
|            Precondition: the set of literals are true in the current model. | ||||
| 
 | ||||
|            By local optimization we understand that x is increased to the largest value within | ||||
|            the signs delineated by the roots of the polynomials in ls. | ||||
|          */ | ||||
|         void maximize(var x, unsigned n, literal const * ls, scoped_anum& val, bool& unbounded); | ||||
| 
 | ||||
|         /**
 | ||||
|            Unit test routine. | ||||
|          */ | ||||
|         void test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result); | ||||
|     }; | ||||
| 
 | ||||
| }; | ||||
|  |  | |||
|  | @ -64,6 +64,13 @@ namespace nlsat { | |||
|             for (unsigned i = 0; i < sz; i++) | ||||
|                 push_back(ls[i]); | ||||
|         } | ||||
|         void append(scoped_literal_vector const& ls) { | ||||
|             append(ls.size(), ls.c_ptr()); | ||||
|         } | ||||
|         void swap(scoped_literal_vector& other) { | ||||
|             SASSERT(&m_solver == &other.m_solver); | ||||
|             m_lits.swap(other.m_lits); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -66,7 +66,6 @@ namespace nlsat { | |||
|         typedef polynomial::cache cache; | ||||
|         typedef ptr_vector<interval_set> interval_set_vector; | ||||
| 
 | ||||
|         solver &               m_solver; | ||||
|         reslimit&              m_rlimit; | ||||
|         small_object_allocator m_allocator; | ||||
|         unsynch_mpq_manager    m_qm; | ||||
|  | @ -159,8 +158,7 @@ namespace nlsat { | |||
|         unsigned               m_stages; | ||||
|         unsigned               m_irrational_assignments; // number of irrational witnesses
 | ||||
| 
 | ||||
|         imp(solver & s, reslimit& rlim, params_ref const & p): | ||||
|             m_solver(s), | ||||
|         imp(solver& s, reslimit& rlim, params_ref const & p): | ||||
|             m_rlimit(rlim), | ||||
|             m_allocator("nlsat"), | ||||
|             m_pm(rlim, m_qm, &m_allocator), | ||||
|  | @ -168,7 +166,7 @@ namespace nlsat { | |||
|             m_am(rlim, m_qm, p, &m_allocator), | ||||
|             m_asm(*this, m_allocator), | ||||
|             m_assignment(m_am), | ||||
|             m_evaluator(m_assignment, m_pm, m_allocator),  | ||||
|             m_evaluator(s, m_assignment, m_pm, m_allocator),  | ||||
|             m_ism(m_evaluator.ism()), | ||||
|             m_num_bool_vars(0), | ||||
|             m_display_var(m_perm), | ||||
|  | @ -183,12 +181,7 @@ namespace nlsat { | |||
|         } | ||||
|          | ||||
|         ~imp() { | ||||
|             m_explain.reset(); | ||||
|             m_lemma.reset(); | ||||
|             m_lazy_clause.reset(); | ||||
|             undo_until_size(0); | ||||
|             del_clauses(); | ||||
|             del_unref_atoms(); | ||||
|             reset(); | ||||
|         } | ||||
| 
 | ||||
|         void mk_true_bvar() { | ||||
|  | @ -216,6 +209,18 @@ namespace nlsat { | |||
|             m_am.updt_params(p.p); | ||||
|         } | ||||
| 
 | ||||
|         void reset() { | ||||
|             m_explain.reset(); | ||||
|             m_lemma.reset(); | ||||
|             m_lazy_clause.reset(); | ||||
|             undo_until_size(0); | ||||
|             del_clauses(); | ||||
|             del_unref_atoms(); | ||||
|             m_cache.reset(); | ||||
|             m_assignment.reset(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         void checkpoint() { | ||||
|             if (!m_rlimit.inc()) throw solver_exception(m_rlimit.get_cancel_msg()); | ||||
|             if (memory::get_allocation_size() > m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG); | ||||
|  | @ -252,6 +257,7 @@ namespace nlsat { | |||
|         } | ||||
| 
 | ||||
|         void inc_ref(bool_var b) { | ||||
|             TRACE("ref", tout << "inc: " << b << "\n";); | ||||
|             if (b == null_bool_var) | ||||
|                 return; | ||||
|             if (m_atoms[b] == 0) | ||||
|  | @ -264,6 +270,7 @@ namespace nlsat { | |||
|         } | ||||
| 
 | ||||
|         void dec_ref(bool_var b) { | ||||
|             TRACE("ref", tout << "dec: " << b << "\n";); | ||||
|             if (b == null_bool_var) | ||||
|                 return; | ||||
|             atom * a = m_atoms[b]; | ||||
|  | @ -412,6 +419,34 @@ namespace nlsat { | |||
|             return x; | ||||
|         } | ||||
| 
 | ||||
|         svector<bool> m_found_vars; | ||||
|         void vars(literal l, var_vector& vs) {                 | ||||
|             vs.reset(); | ||||
|             atom * a = m_atoms[l.var()]; | ||||
|             if (a == 0) { | ||||
|                  | ||||
|             } | ||||
|             else if (a->is_ineq_atom()) { | ||||
|                 unsigned sz = to_ineq_atom(a)->size(); | ||||
|                 var_vector new_vs; | ||||
|                 for (unsigned j = 0; j < sz; j++) { | ||||
|                     m_found_vars.reset(); | ||||
|                     m_pm.vars(to_ineq_atom(a)->p(j), new_vs); | ||||
|                     for (unsigned i = 0; i < new_vs.size(); ++i) { | ||||
|                         if (!m_found_vars.get(new_vs[i], false)) { | ||||
|                             m_found_vars.setx(new_vs[i], true, false); | ||||
|                             vs.push_back(new_vs[i]); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|                 m_pm.vars(to_root_atom(a)->p(), vs); | ||||
|                 //vs.erase(max_var(to_root_atom(a)->p()));
 | ||||
|                 vs.push_back(to_root_atom(a)->x()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void deallocate(ineq_atom * a) { | ||||
|             unsigned obj_sz = ineq_atom::get_obj_size(a->size()); | ||||
|             a->~ineq_atom(); | ||||
|  | @ -491,6 +526,7 @@ namespace nlsat { | |||
|             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); | ||||
|  | @ -726,7 +762,7 @@ namespace nlsat { | |||
| 
 | ||||
|         template<typename Predicate> | ||||
|         void undo_until(Predicate const & pred) { | ||||
|             while (pred()) { | ||||
|             while (pred() && !m_trail.empty()) { | ||||
|                 trail & t = m_trail.back(); | ||||
|                 switch (t.m_kind) { | ||||
|                 case trail::BVAR_ASSIGNMENT: | ||||
|  | @ -803,6 +839,14 @@ namespace nlsat { | |||
|             SASSERT(m_bvalues[b] == l_undef); | ||||
|         } | ||||
| 
 | ||||
|         struct true_pred { | ||||
|             bool operator()() const { return true; } | ||||
|         }; | ||||
| 
 | ||||
|         void undo_until_empty() { | ||||
|             undo_until(true_pred()); | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Create a new scope level | ||||
|         */ | ||||
|  | @ -868,10 +912,11 @@ namespace nlsat { | |||
|             var max = a->max_var(); | ||||
|             if (!m_assignment.is_assigned(max)) | ||||
|                 return l_undef; | ||||
|             TRACE("value_bug", tout << "value of: "; display(tout, l); tout << "\n"; tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n"; | ||||
|                   display_assignment(tout); | ||||
|                   display_bool_assignment(tout);); | ||||
|             return to_lbool(m_evaluator.eval(a, l.sign())); | ||||
|             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"; | ||||
|                   display_assignment(tout);); | ||||
|             return val; | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|  | @ -880,8 +925,10 @@ namespace nlsat { | |||
|         bool is_satisfied(clause const & cls) const { | ||||
|             unsigned sz = cls.size(); | ||||
|             for (unsigned i = 0; i < sz; i++) { | ||||
|                 if (const_cast<imp*>(this)->value(cls[i]) == l_true) | ||||
|                 if (const_cast<imp*>(this)->value(cls[i]) == l_true) { | ||||
|                     TRACE("value_bug:", tout << cls[i] << " := true\n";); | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | @ -984,8 +1031,10 @@ namespace nlsat { | |||
|            If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0 | ||||
|         */ | ||||
|         bool process_arith_clause(clause const & cls, bool satisfy_learned) { | ||||
|             if (!satisfy_learned && m_lazy >= 2 && cls.is_learned()) | ||||
|             if (!satisfy_learned && m_lazy >= 2 && cls.is_learned()) { | ||||
|                 TRACE("nlsat", tout << "skip learned\n";); | ||||
|                 return true; // ignore lemmas in super lazy mode
 | ||||
|             } | ||||
|             SASSERT(m_xk == max_var(cls)); | ||||
|             unsigned num_undef   = 0;                // number of undefined literals
 | ||||
|             unsigned first_undef = UINT_MAX;         // position of the first undefined literal
 | ||||
|  | @ -1064,7 +1113,7 @@ namespace nlsat { | |||
|            If satisfy_learned is true, then (arithmetic) learned clauses are satisfied even if m_lazy > 0 | ||||
|         */ | ||||
|         bool process_clause(clause const & cls, bool satisfy_learned) { | ||||
|             TRACE("nlsat", tout << "processing clause:\n"; display(tout, cls); tout << "\n";); | ||||
|             TRACE("nlsat", tout << "processing clause: "; display(tout, cls); tout << "\n";); | ||||
|             if (is_satisfied(cls)) | ||||
|                 return true; | ||||
|             if (m_xk == null_var) | ||||
|  | @ -1151,7 +1200,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); display_bool_assignment(tout);); | ||||
|                     TRACE("nlsat", tout << "found model\n"; display_assignment(tout);); | ||||
|                     return l_true; // all variables were assigned, and all clauses were satisfied.
 | ||||
|                 } | ||||
|                 TRACE("nlsat", tout << "processing variable ";  | ||||
|  | @ -1186,23 +1235,102 @@ namespace nlsat { | |||
|         lbool check() { | ||||
|             TRACE("nlsat_smt2", display_smt2(tout);); | ||||
|             TRACE("nlsat_fd", tout << "is_full_dimensional: " << is_full_dimensional() << "\n";); | ||||
|             m_xk = null_var; | ||||
|             init_search(); | ||||
|             m_explain.set_full_dimensional(is_full_dimensional()); | ||||
|             if (m_random_order) { | ||||
|             bool reordered = false; | ||||
|             if (!can_reorder()) { | ||||
| 
 | ||||
|             } | ||||
|             else if (m_random_order) { | ||||
|                 shuffle_vars(); | ||||
|                 reordered = true; | ||||
|             } | ||||
|             else if (m_reorder) { | ||||
|                 heuristic_reorder(); | ||||
|                 reordered = true; | ||||
|             } | ||||
|             sort_watched_clauses(); | ||||
|             lbool r = search(); | ||||
|             CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout); display_bool_assignment(tout);); | ||||
|             if (m_reorder) | ||||
|             CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout);); | ||||
|             if (reordered) | ||||
|                 restore_order(); | ||||
|             CTRACE("nlsat_model", r == l_true, tout << "model\n"; display_assignment(tout); display_bool_assignment(tout);); | ||||
|             CTRACE("nlsat_model", r == l_true, tout << "model\n"; display_assignment(tout);); | ||||
|             CTRACE("nlsat", r == l_false, display(tout);); | ||||
|             return r; | ||||
|         } | ||||
| 
 | ||||
|         void init_search() { | ||||
|             undo_until_empty(); | ||||
|             while (m_scope_lvl > 0) { | ||||
|                 undo_new_level(); | ||||
|             } | ||||
|             m_xk = null_var; | ||||
|             for (unsigned i = 0; i < m_bvalues.size(); ++i) { | ||||
|                 m_bvalues[i] = l_undef; | ||||
|             } | ||||
|             m_assignment.reset(); | ||||
|         } | ||||
| 
 | ||||
|         lbool check(literal_vector& assumptions) { | ||||
|             literal_vector result; | ||||
|             unsigned sz = assumptions.size(); | ||||
|             literal const* ptr = assumptions.c_ptr(); | ||||
|             for (unsigned i = 0; i < sz; ++i) { | ||||
|                 mk_clause(1, ptr+i, (assumption)(ptr+i)); | ||||
|             } | ||||
|             lbool r = check(); | ||||
| 
 | ||||
|             if (r == l_false) { | ||||
|                 // collect used literals from m_lemma_assumptions
 | ||||
|                 vector<assumption, false> deps; | ||||
|                 m_asm.linearize(m_lemma_assumptions.get(), deps); | ||||
|                 for (unsigned i = 0; i < deps.size(); ++i) { | ||||
|                     literal const* lp = (literal const*)(deps[i]); | ||||
|                     if (ptr <= lp && lp < ptr + sz) { | ||||
|                         result.push_back(*lp); | ||||
|                     }  | ||||
|                 } | ||||
|             } | ||||
|             collect(assumptions, m_clauses); | ||||
|             collect(assumptions, m_learned); | ||||
|              | ||||
|             assumptions.reset(); | ||||
|             assumptions.append(result); | ||||
|             return r; | ||||
|         } | ||||
| 
 | ||||
|         void collect(literal_vector const& assumptions, clause_vector& clauses) { | ||||
|             unsigned n = clauses.size(); | ||||
|             unsigned j  = 0; | ||||
|             for (unsigned i = 0; i < n; i++) { | ||||
|                 clause * c = clauses[i]; | ||||
|                 if (collect(assumptions, *c)) { | ||||
|                     del_clause(c); | ||||
|                 } | ||||
|                 else { | ||||
|                     clauses[j] = c; | ||||
|                     j++; | ||||
|                 } | ||||
|             } | ||||
|             clauses.shrink(j); | ||||
|         } | ||||
| 
 | ||||
|         bool collect(literal_vector const& assumptions, clause const& c) { | ||||
|             unsigned sz = assumptions.size(); | ||||
|             literal const* ptr = assumptions.c_ptr();             | ||||
|             _assumption_set asms = static_cast<_assumption_set>(c.assumptions()); | ||||
|             if (asms == 0) { | ||||
|                 return false; | ||||
|             } | ||||
|             vector<assumption, false> deps; | ||||
|             m_asm.linearize(asms, deps); | ||||
|             bool found = false; | ||||
|             for (unsigned i = 0; !found && i < deps.size(); ++i) { | ||||
|                 found = ptr <= deps[i] && deps[i] < ptr + sz; | ||||
|             } | ||||
|             return found; | ||||
|         } | ||||
| 
 | ||||
|         // -----------------------
 | ||||
|         //
 | ||||
|         // Conflict Resolution
 | ||||
|  | @ -1447,7 +1575,7 @@ namespace nlsat { | |||
|             TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n"; | ||||
|                   tout << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << "<null>"; tout << "\n"; | ||||
|                   tout << "scope_lvl: " << scope_lvl() << "\n"; | ||||
|                   tout << "current assignment\n"; display_assignment(tout); display_bool_assignment(tout);); | ||||
|                   tout << "current assignment\n"; display_assignment(tout);); | ||||
| 
 | ||||
|             // static unsigned counter = 0;
 | ||||
|             // counter++;
 | ||||
|  | @ -1588,7 +1716,7 @@ namespace nlsat { | |||
|                 conflict_clause = new_cls; | ||||
|                 goto start; | ||||
|             } | ||||
|             TRACE("nlsat_resolve_done", display_assignment(tout); display_bool_assignment(tout);); | ||||
|             TRACE("nlsat_resolve_done", display_assignment(tout);); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|  | @ -1801,6 +1929,15 @@ namespace nlsat { | |||
|             reorder(p.size(), p.c_ptr()); | ||||
|         } | ||||
| 
 | ||||
|         bool can_reorder() const { | ||||
|             for (unsigned i = 0; i < m_atoms.size(); ++i) { | ||||
|                 if (m_atoms[i]) { | ||||
|                     if (m_atoms[i]->is_root_atom()) return false; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Reorder variables using the giving permutation. | ||||
|            p maps internal variables to their new positions | ||||
|  | @ -1921,6 +2058,9 @@ namespace nlsat { | |||
|         void reinit_cache() { | ||||
|             reinit_cache(m_clauses); | ||||
|             reinit_cache(m_learned); | ||||
|             for (unsigned i = 0; i < m_atoms.size(); ++i) { | ||||
|                 reinit_cache(m_atoms[i]); | ||||
|             } | ||||
|         } | ||||
|         void reinit_cache(clause_vector const & cs) { | ||||
|             unsigned sz = cs.size(); | ||||
|  | @ -1934,10 +2074,13 @@ namespace nlsat { | |||
|         } | ||||
|         void reinit_cache(literal l) { | ||||
|             bool_var b = l.var(); | ||||
|             atom * a = m_atoms[b]; | ||||
|             if (a == 0) | ||||
|                 return; | ||||
|             if (a->is_ineq_atom()) { | ||||
|             reinit_cache(m_atoms[b]); | ||||
|         } | ||||
|         void reinit_cache(atom* a) { | ||||
|             if (a == 0) { | ||||
| 
 | ||||
|             } | ||||
|             else if (a->is_ineq_atom()) { | ||||
|                 var max = 0; | ||||
|                 unsigned sz = to_ineq_atom(a)->size(); | ||||
|                 for (unsigned i = 0; i < sz; i++) { | ||||
|  | @ -2073,7 +2216,7 @@ namespace nlsat { | |||
|         //
 | ||||
|         // -----------------------
 | ||||
|          | ||||
|         void display_assignment(std::ostream & out, display_var_proc const & proc) const { | ||||
|         void 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); | ||||
|  | @ -2084,7 +2227,7 @@ namespace nlsat { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void display_bool_assignment(std::ostream & out, display_var_proc const & proc) const { | ||||
|         void 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) { | ||||
|  | @ -2112,12 +2255,13 @@ namespace nlsat { | |||
|             return !first; | ||||
|         } | ||||
| 
 | ||||
|         void display_assignment(std::ostream & out) const {  | ||||
|             display_assignment(out, m_display_var); | ||||
|         void display_num_assignment(std::ostream & out) const {  | ||||
|             display_num_assignment(out, m_display_var); | ||||
|         } | ||||
| 
 | ||||
|         void display_bool_assignment(std::ostream & out) const {  | ||||
|             display_bool_assignment(out, m_display_var); | ||||
|         void display_assignment(std::ostream& out) const { | ||||
|             display_bool_assignment(out); | ||||
|             display_num_assignment(out); | ||||
|         } | ||||
|         | ||||
|         void display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { | ||||
|  | @ -2511,6 +2655,7 @@ namespace nlsat { | |||
| 
 | ||||
|         void display(std::ostream & out) const { | ||||
|             display(out, m_display_var); | ||||
|             display_assignment(out); | ||||
|         } | ||||
| 
 | ||||
|         void display_vars(std::ostream & out) const { | ||||
|  | @ -2562,6 +2707,20 @@ namespace nlsat { | |||
|         return m_imp->check(); | ||||
|     } | ||||
| 
 | ||||
|     lbool solver::check(literal_vector& assumptions) { | ||||
|         return m_imp->check(assumptions); | ||||
|     } | ||||
| 
 | ||||
|     void solver::reset() { | ||||
|         m_imp->reset(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void solver::updt_params(params_ref const & p) { | ||||
|         m_imp->updt_params(p); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void solver::collect_param_descrs(param_descrs & d) { | ||||
|         algebraic_numbers::manager::collect_param_descrs(d); | ||||
|         nlsat_params::collect_param_descrs(d); | ||||
|  | @ -2583,6 +2742,10 @@ namespace nlsat { | |||
|         m_imp->m_display_var.m_proc = &proc; | ||||
|     } | ||||
| 
 | ||||
|     unsigned solver::num_vars() const { | ||||
|         return m_imp->num_vars(); | ||||
|     } | ||||
| 
 | ||||
|     bool solver::is_int(var x) const { | ||||
|         return m_imp->is_int(x); | ||||
|     } | ||||
|  | @ -2590,10 +2753,61 @@ namespace nlsat { | |||
|     bool_var solver::mk_bool_var() { | ||||
|         return m_imp->mk_bool_var(); | ||||
|     } | ||||
|      | ||||
|     literal solver::mk_true() { | ||||
|         return literal(0, false); | ||||
|     } | ||||
| 
 | ||||
|     atom * solver::bool_var2atom(bool_var b) { | ||||
|         return m_imp->m_atoms[b]; | ||||
|     } | ||||
| 
 | ||||
|     void solver::vars(literal l, var_vector& vs) { | ||||
|         m_imp->vars(l, vs); | ||||
|     } | ||||
| 
 | ||||
|     atom_vector const& solver::get_atoms() { | ||||
|         return m_imp->m_atoms; | ||||
|     } | ||||
| 
 | ||||
|     atom_vector const& solver::get_var2eq() { | ||||
|         return m_imp->m_var2eq; | ||||
|     } | ||||
| 
 | ||||
|     evaluator& solver::get_evaluator() { | ||||
|         return m_imp->m_evaluator; | ||||
|     } | ||||
| 
 | ||||
|     explain& solver::get_explain() { | ||||
|         return m_imp->m_explain; | ||||
|     } | ||||
| 
 | ||||
|     void solver::reorder(unsigned sz, var const* p) { | ||||
|         m_imp->reorder(sz, p); | ||||
|     } | ||||
| 
 | ||||
|     void solver::restore_order() { | ||||
|         m_imp->restore_order(); | ||||
|     } | ||||
| 
 | ||||
|     void solver::set_rvalues(assignment const& as) { | ||||
|         m_imp->m_assignment.copy(as); | ||||
|     } | ||||
| 
 | ||||
|     void solver::get_rvalues(assignment& as) { | ||||
|         as.copy(m_imp->m_assignment); | ||||
|     } | ||||
| 
 | ||||
|     void solver::get_bvalues(svector<lbool>& vs) { | ||||
|         vs.reset(); | ||||
|         vs.append(m_imp->m_bvalues); | ||||
|     } | ||||
| 
 | ||||
|     void solver::set_bvalues(svector<lbool> const& vs) { | ||||
|         m_imp->m_bvalues.reset(); | ||||
|         m_imp->m_bvalues.append(vs); | ||||
|         m_imp->m_bvalues.resize(m_imp->m_atoms.size(), l_undef);         | ||||
|     } | ||||
|      | ||||
|     var solver::mk_var(bool is_int) { | ||||
|         return m_imp->mk_var(is_int); | ||||
|  | @ -2631,10 +2845,21 @@ namespace nlsat { | |||
|         m_imp->display(out, l); | ||||
|     } | ||||
| 
 | ||||
|     void solver::display(std::ostream & out, unsigned n, literal const* ls) const { | ||||
|         for (unsigned i = 0; i < n; ++i) { | ||||
|             display(out, ls[i]); | ||||
|             out << ";  "; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void solver::display(std::ostream & out, var x) const { | ||||
|         m_imp->m_display_var(out, x); | ||||
|     } | ||||
| 
 | ||||
|     void solver::display(std::ostream & out, atom const& a) const { | ||||
|         m_imp->display(out, a, m_imp->m_display_var); | ||||
|     } | ||||
| 
 | ||||
|     display_var_proc const & solver::display_proc() const { | ||||
|         return m_imp->m_display_var; | ||||
|     } | ||||
|  |  | |||
|  | @ -28,6 +28,9 @@ Revision History: | |||
| 
 | ||||
| namespace nlsat { | ||||
| 
 | ||||
|     class evaluator; | ||||
|     class explain; | ||||
| 
 | ||||
|     class solver { | ||||
|         struct imp; | ||||
|         imp * m_imp; | ||||
|  | @ -63,7 +66,9 @@ namespace nlsat { | |||
|                   nonlinear arithmetic atom. | ||||
|         */ | ||||
|         bool_var mk_bool_var(); | ||||
|      | ||||
|     | ||||
|         literal  mk_true(); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Create a real/integer variable. | ||||
|         */ | ||||
|  | @ -121,6 +126,48 @@ namespace nlsat { | |||
|         */ | ||||
|         atom * bool_var2atom(bool_var b); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief extract free variables from literal. | ||||
|          */ | ||||
|         void vars(literal l, var_vector& vs); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief provide access to atoms. Used by explain. | ||||
|         */ | ||||
|         atom_vector const& get_atoms(); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Access var -> asserted equality. | ||||
|         */ | ||||
| 
 | ||||
|         atom_vector const& get_var2eq();         | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief expose evaluator. | ||||
|         */ | ||||
|          | ||||
|         evaluator& get_evaluator(); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Access explanation module. | ||||
|          */ | ||||
|         explain& get_explain(); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Access assignments to variables. | ||||
|          */ | ||||
|         void get_rvalues(assignment& as); | ||||
|         void set_rvalues(assignment const& as); | ||||
| 
 | ||||
|         void get_bvalues(svector<lbool>& vs); | ||||
|         void set_bvalues(svector<lbool> const& vs); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief reorder variables.  | ||||
|          */ | ||||
|         void reorder(unsigned sz, var const* permutation); | ||||
|         void restore_order(); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Return number of integer/real variables | ||||
|         */ | ||||
|  | @ -135,6 +182,8 @@ namespace nlsat { | |||
|         // -----------------------
 | ||||
|         lbool check(); | ||||
| 
 | ||||
|         lbool check(literal_vector& assumptions); | ||||
| 
 | ||||
|         // -----------------------
 | ||||
|         //
 | ||||
|         // Model
 | ||||
|  | @ -154,6 +203,7 @@ namespace nlsat { | |||
|         void updt_params(params_ref const & p); | ||||
|         static void collect_param_descrs(param_descrs & d); | ||||
| 
 | ||||
|         void reset(); | ||||
|         void collect_statistics(statistics & st); | ||||
|         void reset_statistics(); | ||||
|         void display_status(std::ostream & out) const; | ||||
|  | @ -174,6 +224,10 @@ namespace nlsat { | |||
|         */ | ||||
|         void display(std::ostream & out, literal l) const; | ||||
| 
 | ||||
|         void display(std::ostream & out, unsigned n, literal const* ls) const; | ||||
| 
 | ||||
|         void display(std::ostream & out, atom const& a) const; | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Display variable | ||||
|         */ | ||||
|  |  | |||
|  | @ -111,6 +111,21 @@ namespace nlsat { | |||
|         struct eq_proc { bool operator()(ineq_atom const * a1, ineq_atom const * a2) const; }; | ||||
|     }; | ||||
| 
 | ||||
|     inline std::ostream& operator<<(std::ostream& out, atom::kind k) { | ||||
|         switch (k) { | ||||
|         case atom::EQ: return out << "="; | ||||
|         case atom::LT: return out << "<"; | ||||
|         case atom::GT: return out << ">"; | ||||
|         case atom::ROOT_EQ: return out << "= root"; | ||||
|         case atom::ROOT_LT: return out << "< root"; | ||||
|         case atom::ROOT_LE: return out << "<= root"; | ||||
|         case atom::ROOT_GT: return out << "> root"; | ||||
|         case atom::ROOT_GE: return out << ">= root"; | ||||
|         default: return out << (int)k; | ||||
|         } | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|     class root_atom : public atom { | ||||
|         friend class solver; | ||||
|         var      m_x; | ||||
|  |  | |||
|  | @ -29,7 +29,9 @@ Notes: | |||
| #include"expr2var.h" | ||||
| #include"arith_decl_plugin.h" | ||||
| #include"tactic.h" | ||||
| #include"ast_smt2_pp.h" | ||||
| #include"ast_pp.h" | ||||
| #include"polynomial.h" | ||||
| #include"algebraic_numbers.h" | ||||
| 
 | ||||
| struct goal2nlsat::imp { | ||||
|     struct nlsat_expr2polynomial : public expr2polynomial { | ||||
|  | @ -124,7 +126,7 @@ struct goal2nlsat::imp { | |||
|         m_qm.neg(d2); | ||||
|         polynomial_ref p(m_pm); | ||||
|         p = m_pm.addmul(d1, m_pm.mk_unit(), p1, d2, m_pm.mk_unit(), p2); | ||||
|         TRACE("goal2nlsat_bug", tout << "p: " << p << "\nk: " << k << "\n";); | ||||
|         TRACE("goal2nlsat_bug", tout << mk_pp(f, m) << " p: " << p << "\nk: " << k << "\n";); | ||||
|         if (is_const(p)) { | ||||
|             int sign; | ||||
|             if (is_zero(p)) | ||||
|  | @ -192,7 +194,7 @@ struct goal2nlsat::imp { | |||
|                 switch (to_app(f)->get_decl_kind()) { | ||||
|                 case OP_TRUE: | ||||
|                 case OP_FALSE: | ||||
|                     TRACE("goal2nlsat", tout << "f: " << mk_ismt2_pp(f, m) << "\n";); | ||||
|                     TRACE("goal2nlsat", tout << "f: " << mk_pp(f, m) << "\n";); | ||||
|                     throw tactic_exception("apply simplify before applying nlsat"); | ||||
|                 case OP_AND: | ||||
|                 case OP_OR: | ||||
|  | @ -257,6 +259,7 @@ struct goal2nlsat::imp { | |||
|             process(g.form(i), g.dep(i)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| struct goal2nlsat::scoped_set_imp { | ||||
|  | @ -289,4 +292,154 @@ void goal2nlsat::operator()(goal const & g, params_ref const & p, nlsat::solver | |||
|     scoped_set_imp setter(*this, local_imp); | ||||
|     local_imp(g); | ||||
| } | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
| struct nlsat2goal::imp { | ||||
|     ast_manager& m; | ||||
|     arith_util   a; | ||||
|     u_map<expr*> const* m_x2t; | ||||
| public: | ||||
|     imp(ast_manager& m):m(m),a(m) {} | ||||
| 
 | ||||
|     expr_ref operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l) { | ||||
|         m_x2t = &x2t; | ||||
|         expr_ref result(m); | ||||
|         expr* t; | ||||
|         if (b2a.find(l.var(), t)) { | ||||
|             result = t; | ||||
|         } | ||||
|         else { | ||||
|             nlsat::atom const* at = s.bool_var2atom(l.var()); | ||||
|             SASSERT(at != 0); | ||||
|             if (at->is_ineq_atom()) { | ||||
|                 nlsat::ineq_atom const* ia = to_ineq_atom(at); | ||||
|                 unsigned sz = ia->size(); | ||||
|                 expr_ref_vector ps(m); | ||||
|                 bool is_int = true; | ||||
|                 for (unsigned i = 0; is_int && i < sz; ++i) { | ||||
|                     is_int = poly_is_int(ia->p(i)); | ||||
|                 } | ||||
|                 for (unsigned i = 0; i < sz; ++i) { | ||||
|                     polynomial::polynomial* p = ia->p(i); | ||||
|                     expr_ref t = poly2expr(s, p, is_int); | ||||
|                     if (ia->is_even(i)) { | ||||
|                         t = a.mk_power(t, a.mk_numeral(rational(2), a.is_int(t))); | ||||
|                     } | ||||
|                     ps.push_back(t); | ||||
|                 } | ||||
|                 result = a.mk_mul_simplify(ps); | ||||
|                 expr_ref zero(m); | ||||
|                 zero = a.mk_numeral(rational(0), a.is_int(result)); | ||||
|                 switch (ia->get_kind()) { | ||||
|                 case nlsat::atom::EQ: | ||||
|                     result = m.mk_eq(result, zero); | ||||
|                     break; | ||||
|                 case nlsat::atom::LT: | ||||
|                     if (l.sign()) { | ||||
|                         l.neg(); | ||||
|                         result = a.mk_ge(result, zero); | ||||
|                     } | ||||
|                     else { | ||||
|                         result = a.mk_lt(result, zero); | ||||
|                     } | ||||
|                     break; | ||||
|                 case nlsat::atom::GT: | ||||
|                     if (l.sign()) { | ||||
|                         l.neg(); | ||||
|                         result = a.mk_le(result, zero); | ||||
|                     } | ||||
|                     else { | ||||
|                         result = a.mk_gt(result, zero); | ||||
|                     } | ||||
|                     break; | ||||
|                 default: | ||||
|                     UNREACHABLE(); | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|                 //nlsat::root_atom const* ra = nlsat::to_root_atom(at);
 | ||||
|                 //ra->i();
 | ||||
|                 //expr_ref p = poly2expr(s, ra->p());
 | ||||
|                 //expr*    x = m_x2t->find(ra->x());
 | ||||
|                 std::ostringstream strm; | ||||
|                 s.display(strm, l.sign()?~l:l); | ||||
|                 result = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (l.sign()) { | ||||
|             result = m.mk_not(result); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     expr_ref poly2expr(nlsat::solver& s, polynomial::polynomial* p, bool is_int) { | ||||
|         expr_ref result(m); | ||||
|         unsigned sz = polynomial::manager::size(p); | ||||
|         expr_ref_vector args(m); | ||||
|         for (unsigned i = 0; i < sz; ++i) { | ||||
|             args.push_back(mono2expr(s,  | ||||
|                                      polynomial::manager::coeff(p, i),  | ||||
|                                      polynomial::manager::get_monomial(p, i), is_int)); | ||||
|         } | ||||
|         result = a.mk_add_simplify(args); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     expr_ref mono2expr(nlsat::solver& s, polynomial::numeral const& c, polynomial::monomial* mon, bool is_int) { | ||||
|         expr_ref result(m); | ||||
|         expr_ref_vector args(m); | ||||
|         unsigned sz = polynomial::manager::size(mon); | ||||
|         for (unsigned i = 0; i < sz; ++i) { | ||||
|             unsigned d = polynomial::manager::degree(mon, i); | ||||
|             expr* t = m_x2t->find(polynomial::manager::get_var(mon, i)); | ||||
|             SASSERT(d >= 1); | ||||
|             if (d == 1) { | ||||
|                 args.push_back(t); | ||||
|             } | ||||
|             else { | ||||
|                 args.push_back(a.mk_power(t, a.mk_numeral(rational(d), a.is_int(t)))); | ||||
|             } | ||||
|         } | ||||
|         if (!s.pm().m().is_one(c)) { | ||||
|             args.push_back(a.mk_numeral(c, is_int)); | ||||
|         } | ||||
|         result = a.mk_mul_simplify(args); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     bool poly_is_int(polynomial::polynomial* p) { | ||||
|         bool is_int = true; | ||||
|         unsigned sz = polynomial::manager::size(p); | ||||
|         for (unsigned i = 0; is_int && i < sz; ++i) { | ||||
|             is_int = mono_is_int(polynomial::manager::get_monomial(p, i)); | ||||
|         } | ||||
|         return is_int; | ||||
|     } | ||||
| 
 | ||||
|     bool mono_is_int(polynomial::monomial* mon) { | ||||
|         bool is_int = true; | ||||
|         unsigned sz = polynomial::manager::size(mon); | ||||
|         for (unsigned i = 0; is_int && i < sz; ++i) { | ||||
|             is_int = a.is_int(m_x2t->find(polynomial::manager::get_var(mon, i))); | ||||
|         } | ||||
|         return is_int; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| nlsat2goal::nlsat2goal(ast_manager& m) { | ||||
|     m_imp = alloc(imp, m); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| nlsat2goal::~nlsat2goal() { | ||||
|     dealloc(m_imp); | ||||
| } | ||||
| 
 | ||||
| expr_ref nlsat2goal::operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l) { | ||||
|     return (*m_imp)(s, b2a, x2t, l); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -57,17 +57,16 @@ class nlsat2goal { | |||
|     struct imp; | ||||
|     imp *  m_imp; | ||||
| public: | ||||
|     nlsat2goal(); | ||||
|     nlsat2goal(ast_manager& m); | ||||
|     ~nlsat2goal(); | ||||
| 
 | ||||
|     static void collect_param_descrs(param_descrs & r); | ||||
| 
 | ||||
|     /**
 | ||||
|        \brief Translate the state of the nlsat engine back into a goal. | ||||
|     */ | ||||
|     void operator()(nlsat::solver const & s, expr2var const & a2b, expr2var const & t2x, | ||||
|                     params_ref const & p, goal & g, model_converter_ref & mc); | ||||
|      | ||||
|        \brief Translate a literal into a formula. | ||||
|     */    | ||||
|     expr_ref operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -514,12 +514,10 @@ namespace opt { | |||
| 
 | ||||
|     void context::init_solver() { | ||||
|         setup_arith_solver(); | ||||
|         #pragma omp critical (opt_context) | ||||
|         { | ||||
|             m_opt_solver = alloc(opt_solver, m, m_params, m_fm); | ||||
|             m_opt_solver->set_logic(m_logic); | ||||
|             m_solver = m_opt_solver.get(); | ||||
|         } | ||||
|         m_opt_solver = alloc(opt_solver, m, m_params, m_fm); | ||||
|         m_opt_solver->set_logic(m_logic); | ||||
|         m_solver = m_opt_solver.get(); | ||||
|      | ||||
|         if (opt_params(m_params).priority() == symbol("pareto") || | ||||
|             (opt_params(m_params).priority() == symbol("lex") && m_objectives.size() > 1)) { | ||||
|             m_opt_solver->ensure_pb(); | ||||
|  | @ -556,10 +554,7 @@ namespace opt { | |||
|         for (unsigned i = 0; i < sz; ++i) { | ||||
|             m_sat_solver->assert_expr(get_solver().get_assertion(i)); | ||||
|         }    | ||||
|         #pragma omp critical (opt_context) | ||||
|         { | ||||
|             m_solver = m_sat_solver.get(); | ||||
|         } | ||||
|         m_solver = m_sat_solver.get();         | ||||
|     } | ||||
| 
 | ||||
|     void context::enable_sls(bool force) { | ||||
|  | @ -649,10 +644,7 @@ namespace opt { | |||
|     void context::add_maxsmt(symbol const& id, unsigned index) { | ||||
|         maxsmt* ms = alloc(maxsmt, *this, index); | ||||
|         ms->updt_params(m_params); | ||||
|         #pragma omp critical (opt_context) | ||||
|         { | ||||
|             m_maxsmts.insert(id, ms); | ||||
|         } | ||||
|         m_maxsmts.insert(id, ms);         | ||||
|     } | ||||
| 
 | ||||
|     bool context::is_numeral(expr* e, rational & n) const { | ||||
|  | @ -1277,10 +1269,7 @@ namespace opt { | |||
|     } | ||||
|         | ||||
|     void context::set_simplify(tactic* tac) { | ||||
|         #pragma omp critical (opt_context) | ||||
|         { | ||||
|             m_simplify = tac; | ||||
|         } | ||||
|         m_simplify = tac;         | ||||
|     } | ||||
| 
 | ||||
|     void context::clear_state() { | ||||
|  | @ -1290,10 +1279,7 @@ namespace opt { | |||
|     } | ||||
| 
 | ||||
|     void context::set_pareto(pareto_base* p) { | ||||
|         #pragma omp critical (opt_context) | ||||
|         { | ||||
|             m_pareto = p; | ||||
|         } | ||||
|         m_pareto = p;         | ||||
|     } | ||||
| 
 | ||||
|     void context::collect_statistics(statistics& stats) const { | ||||
|  |  | |||
							
								
								
									
										928
									
								
								src/qe/nlqsat.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										928
									
								
								src/qe/nlqsat.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,928 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     nlqsat.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Quantifier Satisfiability Solver for nlsat | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-10-17 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #include "nlqsat.h" | ||||
| #include "nlsat_solver.h" | ||||
| #include "nlsat_explain.h" | ||||
| #include "nlsat_assignment.h" | ||||
| #include "qsat.h" | ||||
| #include "quant_hoist.h" | ||||
| #include "goal2nlsat.h" | ||||
| #include "expr2var.h" | ||||
| #include "uint_set.h" | ||||
| #include "ast_util.h" | ||||
| #include "tseitin_cnf_tactic.h" | ||||
| #include "expr_safe_replace.h" | ||||
| #include "ast_pp.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     enum qsat_mode_t { | ||||
|         qsat_t, | ||||
|         elim_t, | ||||
|         interp_t | ||||
|     }; | ||||
| 
 | ||||
|     class nlqsat : public tactic { | ||||
| 
 | ||||
|         typedef unsigned_vector assumption_vector; | ||||
|         typedef nlsat::scoped_literal_vector clause; | ||||
| 
 | ||||
|         struct stats { | ||||
|             unsigned m_num_rounds;         | ||||
|             stats() { reset(); } | ||||
|             void reset() { memset(this, 0, sizeof(*this)); }             | ||||
|         }; | ||||
|          | ||||
|         ast_manager&           m; | ||||
|         qsat_mode_t            m_mode; | ||||
|         params_ref             m_params; | ||||
|         nlsat::solver          m_solver; | ||||
|         tactic_ref             m_nftactic; | ||||
|         nlsat::literal_vector  m_asms; | ||||
|         nlsat::literal_vector  m_cached_asms; | ||||
|         unsigned_vector        m_cached_asms_lim; | ||||
|         nlsat::literal         m_is_true; | ||||
|         nlsat::assignment      m_rmodel;         | ||||
|         svector<lbool>         m_bmodel; | ||||
|         nlsat::assignment      m_rmodel0;         | ||||
|         svector<lbool>         m_bmodel0; | ||||
|         bool                   m_valid_model; | ||||
|         vector<nlsat::var_vector>            m_bound_rvars; | ||||
|         vector<svector<nlsat::bool_var> >    m_bound_bvars; | ||||
|         vector<nlsat::scoped_literal_vector> m_preds; | ||||
|         svector<max_level>                   m_rvar2level; | ||||
|         u_map<max_level>                     m_bvar2level; | ||||
|         expr2var                             m_a2b, m_t2x; | ||||
|         u_map<expr*>                         m_b2a, m_x2t; | ||||
|         volatile bool                        m_cancel; | ||||
|         stats                                m_stats; | ||||
|         statistics                           m_st; | ||||
|         obj_hashtable<expr>                  m_free_vars; | ||||
|         expr_ref_vector                      m_answer; | ||||
|         expr_safe_replace                    m_answer_simplify; | ||||
|         nlsat::literal_vector                m_assumptions; | ||||
|         u_map<expr*>                         m_asm2fml; | ||||
|         expr_ref_vector                      m_trail; | ||||
|          | ||||
|         lbool check_sat() { | ||||
|             while (true) { | ||||
|                 ++m_stats.m_num_rounds; | ||||
|                 check_cancel(); | ||||
|                 init_assumptions();    | ||||
|                 lbool res = m_solver.check(m_asms); | ||||
|                 switch (res) { | ||||
|                 case l_true: | ||||
|                     TRACE("qe", display(tout); ); | ||||
|                     save_model(); | ||||
|                     push(); | ||||
|                     break; | ||||
|                 case l_false: | ||||
|                     if (0 == level()) return l_false; | ||||
|                     if (1 == level() && m_mode == qsat_t) return l_true; | ||||
|                     project(); | ||||
|                     break; | ||||
|                 case l_undef: | ||||
|                     return res; | ||||
|                 } | ||||
|             } | ||||
|             return l_undef; | ||||
|         } | ||||
|          | ||||
|         void init_assumptions() { | ||||
|             unsigned lvl = level(); | ||||
|             m_asms.reset(); | ||||
|             m_asms.push_back(is_exists()?m_is_true:~m_is_true); | ||||
|             m_asms.append(m_assumptions); | ||||
|             TRACE("qe", tout << "model valid: " << m_valid_model << " level: " << lvl << " ";  | ||||
|                   display_assumptions(tout); | ||||
|                   m_solver.display(tout);); | ||||
| 
 | ||||
|             if (!m_valid_model) { | ||||
|                 m_asms.append(m_cached_asms); | ||||
|                 return; | ||||
|             }             | ||||
|             unsave_model(); | ||||
|             if (lvl == 0) { | ||||
|                 SASSERT(m_cached_asms.empty()); | ||||
|                 return; | ||||
|             } | ||||
|             if (lvl <= m_preds.size()) { | ||||
|                 for (unsigned j = 0; j < m_preds[lvl - 1].size(); ++j) { | ||||
|                     add_literal(m_cached_asms, m_preds[lvl - 1][j]); | ||||
|                 } | ||||
|             } | ||||
|             m_asms.append(m_cached_asms); | ||||
|              | ||||
|             for (unsigned i = lvl + 1; i < m_preds.size(); i += 2) { | ||||
|                 for (unsigned j = 0; j < m_preds[i].size(); ++j) { | ||||
|                     nlsat::literal l = m_preds[i][j]; | ||||
|                     max_level lv = m_bvar2level.find(l.var()); | ||||
|                     bool use =  | ||||
|                         (lv.m_fa == i && (lv.m_ex == UINT_MAX || lv.m_ex < lvl)) || | ||||
|                         (lv.m_ex == i && (lv.m_fa == UINT_MAX || lv.m_fa < lvl)); | ||||
|                     if (use) { | ||||
|                         add_literal(m_asms, l); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             TRACE("qe", display(tout); | ||||
|                   for (unsigned i = 0; i < m_asms.size(); ++i) { | ||||
|                       m_solver.display(tout, m_asms[i]); tout << "\n"; | ||||
|                   }); | ||||
|             save_model(); | ||||
|         } | ||||
| 
 | ||||
|         void add_literal(nlsat::literal_vector& lits, nlsat::literal l) { | ||||
|             lbool r = m_solver.value(l); | ||||
|             switch (r) { | ||||
|             case l_true: | ||||
|                 lits.push_back(l); | ||||
|                 break; | ||||
|             case l_false: | ||||
|                 lits.push_back(~l); | ||||
|                 break; | ||||
|             default: | ||||
|                 UNREACHABLE(); | ||||
|                 break;  | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         template<class S, class T> | ||||
|         void insert_set(S& set, T const& vec) { | ||||
|             for (unsigned i = 0; i < vec.size(); ++i) { | ||||
|                 set.insert(vec[i]); | ||||
|             } | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         void mbp(unsigned level, nlsat::scoped_literal_vector& result) { | ||||
|             nlsat::var_vector vars; | ||||
|             uint_set fvars; | ||||
|             extract_vars(level, vars, fvars); | ||||
|             mbp(vars, fvars, result); | ||||
|         } | ||||
| 
 | ||||
|         void extract_vars(unsigned level, nlsat::var_vector& vars, uint_set& fvars) { | ||||
|             for (unsigned i = 0; i < m_bound_rvars.size(); ++i) { | ||||
|                 if (i < level) { | ||||
|                     insert_set(fvars, m_bound_bvars[i]); | ||||
|                 } | ||||
|                 else { | ||||
|                     vars.append(m_bound_rvars[i]); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void mbp(nlsat::var_vector const& vars, uint_set const& fvars, clause& result) { | ||||
|             // 
 | ||||
|             // Also project auxiliary variables from clausification.
 | ||||
|             // 
 | ||||
|             unsave_model(); | ||||
|             nlsat::explain& ex = m_solver.get_explain(); | ||||
|             nlsat::scoped_literal_vector new_result(m_solver); | ||||
|             result.reset(); | ||||
|             // project quantified Boolean variables.
 | ||||
|             for (unsigned i = 0; i < m_asms.size(); ++i) { | ||||
|                 nlsat::literal lit = m_asms[i]; | ||||
|                 if (!m_b2a.contains(lit.var()) || fvars.contains(lit.var())) { | ||||
|                     result.push_back(lit); | ||||
|                 } | ||||
|             } | ||||
|             TRACE("qe", m_solver.display(tout, result.size(), result.c_ptr()); tout << "\n";); | ||||
|             // project quantified real variables.
 | ||||
|             // They are sorted by size, so we project the largest variables first to avoid 
 | ||||
|             // renaming variables. 
 | ||||
|             for (unsigned i = vars.size(); i > 0;) { | ||||
|                 --i; | ||||
|                 new_result.reset(); | ||||
|                 ex.project(vars[i], result.size(), result.c_ptr(), new_result); | ||||
|                 result.swap(new_result); | ||||
|                 TRACE("qe", m_solver.display(tout, result.size(), result.c_ptr()); tout << "\n";); | ||||
|             } | ||||
|             negate_clause(result); | ||||
|         } | ||||
| 
 | ||||
|         void negate_clause(clause& result) { | ||||
|             for (unsigned i = 0; i < result.size(); ++i) { | ||||
|                 result.set(i, ~result[i]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void save_model() { | ||||
|             m_solver.get_rvalues(m_rmodel); | ||||
|             m_solver.get_bvalues(m_bmodel); | ||||
|             m_valid_model = true; | ||||
|             if (is_exists(level())) { | ||||
|                 m_rmodel0.copy(m_rmodel); | ||||
|                 m_bmodel0.reset(); | ||||
|                 m_bmodel0.append(m_bmodel); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void unsave_model() { | ||||
|             SASSERT(m_valid_model); | ||||
|             m_solver.set_rvalues(m_rmodel); | ||||
|             m_solver.set_bvalues(m_bmodel); | ||||
|         } | ||||
|           | ||||
|         void clear_model() { | ||||
|             m_valid_model = false; | ||||
|             m_rmodel.reset(); | ||||
|             m_bmodel.reset(); | ||||
|             m_solver.set_rvalues(m_rmodel); | ||||
|         } | ||||
| 
 | ||||
|         unsigned level() const {  | ||||
|             return m_cached_asms_lim.size(); | ||||
|         } | ||||
| 
 | ||||
|         void enforce_parity(clause& cl) { | ||||
|             cl.push_back(is_exists()?~m_is_true:m_is_true); | ||||
|         } | ||||
| 
 | ||||
|         void add_clause(clause& cl) { | ||||
|             if (cl.empty()) { | ||||
|                 cl.push_back(~m_solver.mk_true()); | ||||
|             } | ||||
|             SASSERT(!cl.empty()); | ||||
|             nlsat::literal_vector lits(cl.size(), cl.c_ptr()); | ||||
|             m_solver.mk_clause(lits.size(), lits.c_ptr()); | ||||
|         } | ||||
| 
 | ||||
|         max_level get_level(clause const& cl) { | ||||
|             return get_level(cl.size(), cl.c_ptr()); | ||||
|         } | ||||
| 
 | ||||
|         max_level get_level(unsigned n, nlsat::literal const* ls) { | ||||
|             max_level level; | ||||
|             for (unsigned i = 0; i < n; ++i) { | ||||
|                 level.merge(get_level(ls[i])); | ||||
|             } | ||||
|             return level; | ||||
|         } | ||||
| 
 | ||||
|         max_level get_level(nlsat::literal l) { | ||||
|             max_level level; | ||||
|             if (m_bvar2level.find(l.var(), level)) { | ||||
|                 return level; | ||||
|             } | ||||
|             nlsat::var_vector vs; | ||||
|             m_solver.vars(l, vs); | ||||
|             TRACE("qe", m_solver.display(tout, l); tout << "\n";); | ||||
|             for (unsigned i = 0; i < vs.size(); ++i) { | ||||
|                 level.merge(m_rvar2level[vs[i]]); | ||||
|             } | ||||
|             set_level(l.var(), level); | ||||
|             return level; | ||||
|         } | ||||
| 
 | ||||
|         void set_level(nlsat::bool_var v, max_level const& level) { | ||||
|             unsigned k = level.max(); | ||||
|             while (m_preds.size() <= k) { | ||||
|                 m_preds.push_back(nlsat::scoped_literal_vector(m_solver)); | ||||
|             } | ||||
|             nlsat::literal l(v, false); | ||||
|             m_preds[k].push_back(l); | ||||
|             m_bvar2level.insert(v, level);             | ||||
|             TRACE("qe", m_solver.display(tout, l); tout << ": " << level << "\n";); | ||||
|         } | ||||
|          | ||||
|         void project() { | ||||
|             TRACE("qe", display_assumptions(tout);); | ||||
|             if (!m_valid_model) { | ||||
|                 pop(1); | ||||
|                 return; | ||||
|             } | ||||
|             if (m_mode == elim_t) { | ||||
|                 project_qe(); | ||||
|                 return; | ||||
|             } | ||||
|             SASSERT(level() >= 2); | ||||
|             unsigned num_scopes; | ||||
|             clause cl(m_solver); | ||||
|             mbp(level()-1, cl);             | ||||
|              | ||||
|             max_level clevel = get_level(cl); | ||||
|             enforce_parity(cl); | ||||
|             add_clause(cl); | ||||
| 
 | ||||
|             if (clevel.max() == UINT_MAX) { | ||||
|                 num_scopes = 2*(level()/2); | ||||
|             } | ||||
|             else { | ||||
|                 SASSERT(clevel.max() + 2 <= level()); | ||||
|                 num_scopes = level() - clevel.max(); | ||||
|                 if ((num_scopes % 2) != 0) { | ||||
|                     --num_scopes; | ||||
|                 } | ||||
|                 SASSERT(num_scopes >= 2); | ||||
|             } | ||||
|              | ||||
|             TRACE("qe", tout << "backtrack: " << num_scopes << "\n";); | ||||
|             pop(num_scopes);  | ||||
|         } | ||||
| 
 | ||||
|         void project_qe() { | ||||
|             SASSERT(level() >= 1 && m_mode == elim_t && m_valid_model); | ||||
|             clause cl(m_solver); | ||||
|             mbp(std::max(1u, level()-1), cl);             | ||||
|              | ||||
|             expr_ref fml = clause2fml(cl); | ||||
|             TRACE("qe", tout << level() << ": " << fml << "\n";); | ||||
|             max_level clevel = get_level(cl); | ||||
|             if (level() == 1 || clevel.max() == 0) { | ||||
|                 add_assumption_literal(cl, fml);            | ||||
|             } | ||||
|             else { | ||||
|                 enforce_parity(cl); | ||||
|             } | ||||
|             add_clause(cl); | ||||
| 
 | ||||
|             if (level() == 1) { // is_forall() && clevel.max() == 0
 | ||||
|                 add_to_answer(fml); | ||||
|             } | ||||
| 
 | ||||
|             if (level() == 1) { | ||||
|                 pop(1); | ||||
|             } | ||||
|             else { | ||||
|                 pop(2); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void add_to_answer(expr_ref& fml) { | ||||
|             m_answer_simplify(fml); | ||||
|             expr* e; | ||||
|             if (m.is_not(fml, e)) { | ||||
|                 m_answer_simplify.insert(e, m.mk_false()); | ||||
|             } | ||||
|             else { | ||||
|                 m_answer_simplify.insert(fml, m.mk_true()); | ||||
|             } | ||||
|             m_answer.push_back(fml); | ||||
|         } | ||||
| 
 | ||||
|         expr_ref clause2fml(nlsat::scoped_literal_vector const& clause) { | ||||
|             expr_ref_vector fmls(m); | ||||
|             expr_ref fml(m); | ||||
|             expr* t; | ||||
|             nlsat2goal n2g(m); | ||||
|             for (unsigned i = 0; i < clause.size(); ++i) { | ||||
|                 nlsat::literal l = clause[i]; | ||||
|                 if (m_asm2fml.find(l.var(), t)) { | ||||
|                     fml = t; | ||||
|                     if (l.sign()) { | ||||
|                         fml = push_not(fml); | ||||
|                     } | ||||
|                     SASSERT(l.sign()); | ||||
|                     fmls.push_back(fml); | ||||
|                 } | ||||
|                 else { | ||||
|                     fmls.push_back(n2g(m_solver, m_b2a, m_x2t, l)); | ||||
|                 } | ||||
|             } | ||||
|             fml = mk_or(fmls); | ||||
|             return fml; | ||||
|         } | ||||
| 
 | ||||
|         void add_assumption_literal(clause& clause, expr* fml) { | ||||
|             nlsat::bool_var b = m_solver.mk_bool_var(); | ||||
|             clause.push_back(nlsat::literal(b, true)); | ||||
|             m_assumptions.push_back(nlsat::literal(b, false));  | ||||
|             m_asm2fml.insert(b, fml); | ||||
|             m_trail.push_back(fml);             | ||||
|             m_bvar2level.insert(b, max_level()); | ||||
|         } | ||||
| 
 | ||||
|         bool is_exists() const { return is_exists(level()); } | ||||
|         bool is_forall() const { return is_forall(level()); } | ||||
|         bool is_exists(unsigned level) const { return (level % 2) == 0; }         | ||||
|         bool is_forall(unsigned level) const { return is_exists(level+1); } | ||||
| 
 | ||||
|         void check_cancel() { | ||||
|             if (m_cancel) { | ||||
|                 throw tactic_exception(TACTIC_CANCELED_MSG); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void reset() { | ||||
|             //m_solver.reset();
 | ||||
|             m_asms.reset(); | ||||
|             m_cached_asms.reset(); | ||||
|             m_cached_asms_lim.reset(); | ||||
|             m_is_true = nlsat::null_literal; | ||||
|             m_rmodel.reset(); | ||||
|             m_valid_model = false; | ||||
|             m_bound_rvars.reset(); | ||||
|             m_bound_bvars.reset(); | ||||
|             m_preds.reset(); | ||||
|             m_rvar2level.reset(); | ||||
|             m_bvar2level.reset(); | ||||
|             m_t2x.reset(); | ||||
|             m_a2b.reset(); | ||||
|             m_b2a.reset(); | ||||
|             m_x2t.reset(); | ||||
|             m_cancel = false; | ||||
|             m_st.reset();         | ||||
|             m_solver.collect_statistics(m_st); | ||||
|             m_free_vars.reset(); | ||||
|             m_answer.reset(); | ||||
|             m_answer_simplify.reset(); | ||||
|             m_assumptions.reset(); | ||||
|             m_asm2fml.reset(); | ||||
|             m_trail.reset(); | ||||
|         } | ||||
| 
 | ||||
|         void push() { | ||||
|             m_cached_asms_lim.push_back(m_cached_asms.size()); | ||||
|         } | ||||
| 
 | ||||
|         void pop(unsigned num_scopes) { | ||||
|             clear_model(); | ||||
|             unsigned new_level = level() - num_scopes; | ||||
|             m_cached_asms.shrink(m_cached_asms_lim[new_level]); | ||||
|             m_cached_asms_lim.shrink(new_level); | ||||
|         } | ||||
| 
 | ||||
|         void display(std::ostream& out) { | ||||
|             display_preds(out); | ||||
|             display_assumptions(out); | ||||
|             m_solver.display(out << "solver:\n"); | ||||
|         } | ||||
| 
 | ||||
|         void display_assumptions(std::ostream& out) { | ||||
|             m_solver.display(out << "assumptions: ", m_asms.size(), m_asms.c_ptr()); | ||||
|             out << "\n"; | ||||
|         } | ||||
| 
 | ||||
|         void display_preds(std::ostream& out) { | ||||
|             for (unsigned i = 0; i < m_preds.size(); ++i) {                 | ||||
|                 m_solver.display(out << i << ": ", m_preds[i].size(), m_preds[i].c_ptr()); | ||||
|                 out << "\n"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // expr -> nlsat::solver
 | ||||
| 
 | ||||
|         void hoist(expr_ref& fml) { | ||||
|             quantifier_hoister hoist(m); | ||||
|             vector<app_ref_vector> qvars; | ||||
|             app_ref_vector vars(m); | ||||
|             bool is_forall = false;    | ||||
|             pred_abs abs(m); | ||||
|             abs.get_free_vars(fml, vars); | ||||
|             insert_set(m_free_vars, vars); | ||||
|             qvars.push_back(vars);  | ||||
|             vars.reset();     | ||||
|             if (m_mode == elim_t) { | ||||
|                 is_forall = true; | ||||
|                 hoist.pull_quantifier(is_forall, fml, vars); | ||||
|                 qvars.push_back(vars); | ||||
|             } | ||||
|             else { | ||||
|                 hoist.pull_quantifier(is_forall, fml, vars); | ||||
|                 qvars.back().append(vars);             | ||||
|             } | ||||
|             do { | ||||
|                 is_forall = !is_forall; | ||||
|                 vars.reset(); | ||||
|                 hoist.pull_quantifier(is_forall, fml, vars); | ||||
|                 qvars.push_back(vars); | ||||
|             } | ||||
|             while (!vars.empty()); | ||||
|             SASSERT(qvars.back().empty());  | ||||
|             init_expr2var(qvars); | ||||
| 
 | ||||
|             goal2nlsat g2s; | ||||
| 
 | ||||
|             expr_ref is_true(m), fml1(m), fml2(m); | ||||
|             is_true = m.mk_fresh_const("is_true", m.mk_bool_sort()); | ||||
|             fml = m.mk_iff(is_true, fml); | ||||
|             goal_ref g = alloc(goal, m); | ||||
|             g->assert_expr(fml); | ||||
|             proof_converter_ref pc; | ||||
|             expr_dependency_ref core(m); | ||||
|             model_converter_ref mc; | ||||
|             goal_ref_buffer result; | ||||
|             (*m_nftactic)(g, result, mc, pc, core); | ||||
|             SASSERT(result.size() == 1); | ||||
|             TRACE("qe", result[0]->display(tout);); | ||||
|             g2s(*result[0], m_params, m_solver, m_a2b, m_t2x); | ||||
| 
 | ||||
|             // insert variables and their levels.
 | ||||
|             for (unsigned i = 0; i < qvars.size(); ++i) { | ||||
|                 m_bound_bvars.push_back(svector<nlsat::bool_var>()); | ||||
|                 m_bound_rvars.push_back(nlsat::var_vector()); | ||||
|                 max_level lvl; | ||||
|                 if (is_exists(i)) lvl.m_ex = i; else lvl.m_fa = i; | ||||
|                 for (unsigned j = 0; j < qvars[i].size(); ++j) { | ||||
|                     app* v = qvars[i][j].get(); | ||||
| 
 | ||||
|                     if (m_a2b.is_var(v)) { | ||||
|                         SASSERT(m.is_bool(v)); | ||||
|                         nlsat::bool_var b = m_a2b.to_var(v); | ||||
|                         m_bound_bvars.back().push_back(b); | ||||
|                         set_level(b, lvl); | ||||
|                     } | ||||
|                     else if (m_t2x.is_var(v)) { | ||||
|                         nlsat::var w = m_t2x.to_var(v); | ||||
|                         TRACE("qe", tout << mk_pp(v, m) << " |-> " << w << "\n";); | ||||
|                         m_bound_rvars.back().push_back(w); | ||||
|                         m_rvar2level.setx(w, lvl, max_level()); | ||||
|                     } | ||||
|                     else { | ||||
|                         TRACE("qe", tout << mk_pp(v, m) << " not found\n";); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             init_var2expr(); | ||||
|             m_is_true = nlsat::literal(m_a2b.to_var(is_true), false); | ||||
|             // insert literals from arithmetical sub-formulas
 | ||||
|             nlsat::atom_vector const& atoms = m_solver.get_atoms(); | ||||
|             TRACE("qe", m_solver.display(tout); ); | ||||
|             for (unsigned i = 0; i < atoms.size(); ++i) { | ||||
|                 if (atoms[i]) { | ||||
|                     get_level(nlsat::literal(i, false)); | ||||
|                 } | ||||
|             } | ||||
|             TRACE("qe", tout << fml << "\n";); | ||||
|         } | ||||
| 
 | ||||
|         void init_expr2var(vector<app_ref_vector> const& qvars) { | ||||
|             for (unsigned i = 0; i < qvars.size(); ++i) { | ||||
|                 init_expr2var(qvars[i]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void init_expr2var(app_ref_vector const& qvars) { | ||||
|             for (unsigned i = 0; i < qvars.size(); ++i) { | ||||
|                 app* v = qvars[i]; | ||||
|                 if (m.is_bool(v)) { | ||||
|                     m_a2b.insert(v, m_solver.mk_bool_var()); | ||||
|                 } | ||||
|                 else { | ||||
|                     // TODO: assert it is of type Real.
 | ||||
|                     m_t2x.insert(v, m_solver.mk_var(false)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void init_var2expr() { | ||||
|             expr2var::iterator it = m_t2x.begin(), end = m_t2x.end(); | ||||
|             for (; it != end; ++it) { | ||||
|                 m_x2t.insert(it->m_value, it->m_key); | ||||
|             } | ||||
|             it = m_a2b.begin(), end = m_a2b.end(); | ||||
|             for (; it != end; ++it) { | ||||
|                 m_b2a.insert(it->m_value, it->m_key); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|          | ||||
|         // Return false if nlsat assigned noninteger value to an integer variable.
 | ||||
|         // [copied from nlsat_tactic.cpp]
 | ||||
|         bool mk_model(model_converter_ref & mc) { | ||||
|             bool ok = true; | ||||
|             model_ref md = alloc(model, m); | ||||
|             arith_util util(m); | ||||
|             expr2var::iterator it = m_t2x.begin(), end = m_t2x.end(); | ||||
|             for (; it != end; ++it) { | ||||
|                 nlsat::var x = it->m_value; | ||||
|                 expr * t = it->m_key; | ||||
|                 if (!is_uninterp_const(t) || !m_free_vars.contains(t)) | ||||
|                     continue; | ||||
|                 expr * v; | ||||
|                 try { | ||||
|                     v = util.mk_numeral(m_rmodel0.value(x), util.is_int(t)); | ||||
|                 } | ||||
|                 catch (z3_error & ex) { | ||||
|                     throw ex; | ||||
|                 } | ||||
|                 catch (z3_exception &) { | ||||
|                     v = util.mk_to_int(util.mk_numeral(m_rmodel0.value(x), false)); | ||||
|                     ok = false; | ||||
|                 } | ||||
|                 md->register_decl(to_app(t)->get_decl(), v); | ||||
|             } | ||||
|             it = m_a2b.begin(), end = m_a2b.end(); | ||||
|             for (; it != end; ++it) { | ||||
|                 expr * a = it->m_key; | ||||
|                 nlsat::bool_var b = it->m_value; | ||||
|                 if (a == 0 || !is_uninterp_const(a) || b == m_is_true.var() || !m_free_vars.contains(a)) | ||||
|                     continue; | ||||
|                 lbool val = m_bmodel0.get(b, l_undef); | ||||
|                 if (val == l_undef) | ||||
|                     continue; // don't care
 | ||||
|                 md->register_decl(to_app(a)->get_decl(), val == l_true ? m.mk_true() : m.mk_false()); | ||||
|             } | ||||
|             mc = model2model_converter(md.get()); | ||||
|             return ok; | ||||
|         } | ||||
| 
 | ||||
|     public: | ||||
|         nlqsat(ast_manager& m, qsat_mode_t mode, params_ref const& p): | ||||
|             m(m), | ||||
|             m_mode(mode), | ||||
|             m_params(p), | ||||
|             m_solver(m.limit(), p), | ||||
|             m_nftactic(0), | ||||
|             m_rmodel(m_solver.am()), | ||||
|             m_rmodel0(m_solver.am()), | ||||
|             m_valid_model(false), | ||||
|             m_a2b(m), | ||||
|             m_t2x(m), | ||||
|             m_cancel(false), | ||||
|             m_answer(m), | ||||
|             m_answer_simplify(m), | ||||
|             m_trail(m) | ||||
|         { | ||||
|             m_solver.get_explain().set_signed_project(true); | ||||
|             m_nftactic = mk_tseitin_cnf_tactic(m); | ||||
|         } | ||||
| 
 | ||||
|         virtual ~nlqsat() { | ||||
|         } | ||||
| 
 | ||||
|         void updt_params(params_ref const & p) { | ||||
|             params_ref p2(p); | ||||
|             p2.set_bool("factor", false); | ||||
|             m_solver.updt_params(p2); | ||||
|         } | ||||
|          | ||||
|         void collect_param_descrs(param_descrs & r) { | ||||
|         } | ||||
| 
 | ||||
|          | ||||
|         void operator()(/* in */  goal_ref const & in,  | ||||
|                         /* out */ goal_ref_buffer & result,  | ||||
|                         /* out */ model_converter_ref & mc,  | ||||
|                         /* out */ proof_converter_ref & pc, | ||||
|                         /* out */ expr_dependency_ref & core) { | ||||
| 
 | ||||
|             tactic_report report("nlqsat-tactic", *in); | ||||
| 
 | ||||
|             ptr_vector<expr> fmls; | ||||
|             expr_ref fml(m); | ||||
|             mc = 0; pc = 0; core = 0; | ||||
|             in->get_formulas(fmls); | ||||
|             fml = mk_and(m, fmls.size(), fmls.c_ptr()); | ||||
|             if (m_mode == elim_t) { | ||||
|                 fml = m.mk_not(fml); | ||||
|             }                          | ||||
|             reset(); | ||||
|             TRACE("qe", tout << fml << "\n";); | ||||
|             hoist(fml); | ||||
|             TRACE("qe", tout << "ex: " << fml << "\n";); | ||||
|             lbool is_sat = check_sat(); | ||||
|              | ||||
|             switch (is_sat) { | ||||
|             case l_false: | ||||
|                 in->reset(); | ||||
|                 in->inc_depth(); | ||||
|                 if (m_mode == elim_t) { | ||||
|                     fml = mk_and(m_answer); | ||||
|                 } | ||||
|                 else { | ||||
|                     fml = m.mk_false(); | ||||
|                 } | ||||
|                 in->assert_expr(fml); | ||||
|                 result.push_back(in.get()); | ||||
|                 break; | ||||
|             case l_true: | ||||
|                 SASSERT(m_mode == qsat_t); | ||||
|                 in->reset(); | ||||
|                 in->inc_depth(); | ||||
|                 result.push_back(in.get()); | ||||
|                 if (in->models_enabled()) { | ||||
|                     VERIFY(mk_model(mc)); | ||||
|                 } | ||||
|                 break; | ||||
|             case l_undef: | ||||
|                 result.push_back(in.get()); | ||||
|                 std::string s = "search failed"; | ||||
|                 throw tactic_exception(s.c_str());  | ||||
|             }         | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         void collect_statistics(statistics & st) const { | ||||
|             st.copy(m_st); | ||||
|             st.update("qsat num rounds", m_stats.m_num_rounds);  | ||||
|         } | ||||
| 
 | ||||
|         void reset_statistics() { | ||||
|             m_stats.reset(); | ||||
|             m_solver.reset_statistics(); | ||||
|         } | ||||
| 
 | ||||
|         void cleanup() { | ||||
|             reset(); | ||||
|         } | ||||
|          | ||||
|         void set_logic(symbol const & l) { | ||||
|         } | ||||
|          | ||||
|         void set_progress_callback(progress_callback * callback) { | ||||
|         } | ||||
|          | ||||
|         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<expr> 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 | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p) { | ||||
|     return alloc(qe::nlqsat, m, qe::qsat_t, p); | ||||
| } | ||||
| 
 | ||||
| tactic * mk_nlqe_tactic(ast_manager & m, params_ref const& p) { | ||||
|     return alloc(qe::nlqsat, m, qe::elim_t, p); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										38
									
								
								src/qe/nlqsat.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/qe/nlqsat.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     nlqsat.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Quantifier Satisfiability Solver for nlsat | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-10-17 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #ifndef QE_NLQSAT_H__ | ||||
| #define QE_NLQSAT_H__ | ||||
| 
 | ||||
| #include "tactic.h" | ||||
| 
 | ||||
| 
 | ||||
| tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p = params_ref()); | ||||
| tactic * mk_nlqe_tactic(ast_manager & m, params_ref const& p = params_ref()); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|   ADD_TACTIC("nlqsat", "apply a NL-QSAT solver.", "mk_nlqsat_tactic(m, p)")  | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| // TBD_TACTIC("nlqe", "apply a NL-QE solver.", "mk_nlqe_tactic(m, p)") 
 | ||||
| 
 | ||||
| #endif  | ||||
|  | @ -36,7 +36,6 @@ Revision History: | |||
| #include "expr_functors.h" | ||||
| #include "quant_hoist.h" | ||||
| #include "bool_rewriter.h" | ||||
| #include "qe_util.h" | ||||
| #include "th_rewriter.h" | ||||
| #include "smt_kernel.h" | ||||
| #include "model_evaluator.h" | ||||
|  | @ -2281,7 +2280,7 @@ namespace qe { | |||
|         }     | ||||
|     } | ||||
| 
 | ||||
|     static void extract_vars(quantifier* q, expr_ref& new_body, app_ref_vector& vars) { | ||||
|     void extract_vars(quantifier* q, expr_ref& new_body, app_ref_vector& vars) { | ||||
|         ast_manager& m = new_body.get_manager(); | ||||
|         expr_ref tmp(m); | ||||
|         unsigned nd = q->get_num_decls(); | ||||
|  |  | |||
|  | @ -223,6 +223,8 @@ namespace qe { | |||
| 
 | ||||
|     qe_solver_plugin* mk_arith_plugin(i_solver_context& ctx, bool produce_models, smt_params& p); | ||||
| 
 | ||||
|     void extract_vars(quantifier* q, expr_ref& new_body, app_ref_vector& vars); | ||||
| 
 | ||||
|     class def_vector { | ||||
|         func_decl_ref_vector m_vars; | ||||
|         expr_ref_vector      m_defs; | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -9,16 +9,33 @@ Copyright (c) 2015 Microsoft Corporation | |||
| #define QE_ARITH_H_ | ||||
| 
 | ||||
| #include "model.h" | ||||
| #include "arith_decl_plugin.h" | ||||
| #include "qe_mbp.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     /**
 | ||||
|        Loos-Weispfenning model-based projection for a basic conjunction. | ||||
|        Lits is a vector of literals. | ||||
|        return vector of variables that could not be projected. | ||||
|      */ | ||||
|     expr_ref arith_project(model& model, app_ref_vector& vars, expr_ref_vector const& lits); | ||||
| 
 | ||||
|     expr_ref arith_project(model& model, app_ref_vector& vars, expr* fml); | ||||
|     class arith_project_plugin : public project_plugin { | ||||
|         struct imp; | ||||
|         imp* m_imp; | ||||
|     public: | ||||
|         arith_project_plugin(ast_manager& m); | ||||
|         virtual ~arith_project_plugin(); | ||||
|         virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); | ||||
|         virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); | ||||
|         virtual family_id get_family_id(); | ||||
|     }; | ||||
| 
 | ||||
|     bool arith_project(model& model, app* var, expr_ref_vector& lits); | ||||
| 
 | ||||
|     // match e := t mod k = 0.
 | ||||
|     bool is_divides(arith_util& a, expr* e, rational& k, expr_ref& t); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ Revision History: | |||
| #include "nlarith_util.h" | ||||
| #include "model_evaluator.h" | ||||
| #include "smt_kernel.h" | ||||
| #include "qe_arith.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|  | @ -266,23 +267,8 @@ namespace qe { | |||
|         // 
 | ||||
|         // match 0 == p mod k, p mod k == 0
 | ||||
|         //
 | ||||
|         bool is_divides(app* e, numeral& k, expr_ref& p) { | ||||
|             expr* e1, *e2; | ||||
|             if (!m.is_eq(e, e1, e2)) { | ||||
|                 return false; | ||||
|             } | ||||
|             return is_divides(e1, e2, k, p) || is_divides(e2, e1, k, p); | ||||
|         } | ||||
|      | ||||
|         bool is_divides(expr* e1, expr* e2, numeral& k, expr_ref& p) {   | ||||
|             if (m_arith.is_mod(e2) &&  | ||||
|                 m_arith.is_numeral(e1, k) &&  | ||||
|                 k.is_zero() && | ||||
|                 m_arith.is_numeral(to_app(e2)->get_arg(1), k)) { | ||||
|                 p = to_app(e2)->get_arg(0); | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         bool is_divides(expr* e, numeral& k, expr_ref& p) { | ||||
|             return qe::is_divides(m_arith, e, k, p); | ||||
|         } | ||||
| 
 | ||||
|         bool is_not_divides(app* e, app_ref& n, numeral& k, expr_ref& p) { | ||||
|  |  | |||
							
								
								
									
										427
									
								
								src/qe/qe_arrays.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										427
									
								
								src/qe/qe_arrays.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,427 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qe_arrays.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Model based projection for arrays | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-06-13 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| 
 | ||||
| #include "qe_arrays.h" | ||||
| #include "rewriter_def.h" | ||||
| #include "expr_functors.h" | ||||
| #include "expr_safe_replace.h" | ||||
| #include "lbool.h" | ||||
| #include "ast_util.h" | ||||
| #include "ast_pp.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     struct array_project_plugin::imp { | ||||
| 
 | ||||
|         // rewriter or direct procedure.
 | ||||
|         struct rw_cfg : public default_rewriter_cfg { | ||||
|             ast_manager&    m; | ||||
|             array_util&     a; | ||||
|             expr_ref_vector m_lits; | ||||
|             model*          m_model;  | ||||
|             imp*            m_imp; | ||||
|              | ||||
|             rw_cfg(ast_manager& m, array_util& a): | ||||
|                 m(m), a(a), m_lits(m), m_model(0) {} | ||||
|              | ||||
|             br_status reduce_app(func_decl* f, unsigned n, expr* const* args, expr_ref& result, proof_ref & pr) { | ||||
|                 if (a.is_select(f) && a.is_store(args[0])) {                     | ||||
|                     expr_ref val1(m), val2(m);  | ||||
|                     app* b = to_app(args[0]); | ||||
|                     SASSERT(b->get_num_args() == n + 1); | ||||
|                     for (unsigned i = 1; i < n; ++i) { | ||||
|                         expr* arg1 = args[i]; | ||||
|                         expr* arg2 = b->get_arg(i); | ||||
|                         if (arg1 == arg2) { | ||||
|                             val1 = val2 = arg1; | ||||
|                         } | ||||
|                         else { | ||||
|                             VERIFY(m_model->eval(arg1, val1)); | ||||
|                             VERIFY(m_model->eval(arg2, val2)); | ||||
|                         } | ||||
|                         switch(compare(val1, val2)) { | ||||
|                         case l_true: | ||||
|                             if (arg1 != arg2) { | ||||
|                                 m_lits.push_back(m.mk_eq(arg1, arg2)); | ||||
|                             } | ||||
|                             break; | ||||
|                         case l_false: { | ||||
|                             ptr_vector<expr> new_args; | ||||
|                             if (i > 0) { | ||||
|                                 m_lits.resize(m_lits.size() - i); | ||||
|                             } | ||||
|                             m_lits.push_back(m.mk_not(m.mk_eq(arg1, arg2))); | ||||
|                             new_args.push_back(b->get_arg(0)); | ||||
|                             new_args.append(n-1, args+1); | ||||
|                             result = m.mk_app(f, n, new_args.c_ptr()); | ||||
|                             return BR_REWRITE1; | ||||
|                         } | ||||
|                         case l_undef: | ||||
|                             return BR_FAILED; | ||||
|                         } | ||||
|                     } | ||||
|                     result = b->get_arg(n); | ||||
|                     return BR_DONE; | ||||
|                 } | ||||
|                 return BR_FAILED; | ||||
|             } | ||||
| 
 | ||||
|             lbool compare(expr* x, expr* y) { | ||||
|                 NOT_IMPLEMENTED_YET(); | ||||
|                 return l_undef; | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         struct indices { | ||||
|             expr_ref_vector m_values; | ||||
|             expr* const*    m_vars; | ||||
| 
 | ||||
|             indices(ast_manager& m, model& model, unsigned n, expr* const* vars):  | ||||
|                 m_values(m), m_vars(vars) { | ||||
|                 expr_ref val(m); | ||||
|                 for (unsigned i = 0; i < n; ++i) { | ||||
|                     VERIFY(model.eval(vars[i], val)); | ||||
|                     m_values.push_back(val); | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|          | ||||
|         ast_manager& m; | ||||
|         array_util   a; | ||||
|         scoped_ptr<contains_app> m_var; | ||||
|          | ||||
|         imp(ast_manager& m): m(m), a(m) {} | ||||
|         ~imp() {} | ||||
| 
 | ||||
|         virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
| 
 | ||||
|             TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;); | ||||
|             m_var = alloc(contains_app, m, var); | ||||
| 
 | ||||
|             // reduce select-store redeces based on model.
 | ||||
|             // rw_cfg rw(m);
 | ||||
|             // rw(lits);
 | ||||
| 
 | ||||
|             // try first to solve for var.
 | ||||
|             if (solve_eq(model, vars, lits)) { | ||||
|                 return true; | ||||
|             }  | ||||
| 
 | ||||
|             app_ref_vector selects(m); | ||||
| 
 | ||||
|             // check that only non-select occurrences are in disequalities.
 | ||||
|             if (!check_diseqs(lits, selects)) { | ||||
|                 TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // remove disequalities.
 | ||||
|             elim_diseqs(lits); | ||||
| 
 | ||||
|             // Ackerman reduction on remaining select occurrences
 | ||||
|             // either replace occurrences by model value or other node
 | ||||
|             // that is congruent to model value.
 | ||||
| 
 | ||||
|             ackermanize_select(model, selects, vars, lits); | ||||
|             | ||||
|             TRACE("qe", tout << selects << "\n" << lits << "\n";); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             expr_ref_vector vals(m), reps(m); | ||||
|             expr_ref val(m); | ||||
|             expr_safe_replace sub(m); | ||||
| 
 | ||||
|             if (selects.empty()) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             app_ref sel(m); | ||||
|             for (unsigned i = 0; i < selects.size(); ++i) {                 | ||||
|                 sel = m.mk_fresh_const("sel", m.get_sort(selects[i])); | ||||
|                 VERIFY (model.eval(selects[i], val)); | ||||
|                 model.register_decl(sel->get_decl(), val); | ||||
|                 vals.push_back(to_app(val)); | ||||
|                 reps.push_back(val);               // TODO: direct pass could handle nested selects.
 | ||||
|                 vars.push_back(sel); | ||||
|                 sub.insert(selects[i], val); | ||||
|             } | ||||
| 
 | ||||
|             sub(lits); | ||||
|             remove_true(lits); | ||||
|             project_plugin::partition_args(model, selects, lits); | ||||
|             project_plugin::partition_values(model, reps, lits); | ||||
|         } | ||||
| 
 | ||||
|         void remove_true(expr_ref_vector& lits) { | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 if (m.is_true(lits[i].get())) { | ||||
|                     project_plugin::erase(lits, i); | ||||
|                 } | ||||
|             }             | ||||
|         } | ||||
| 
 | ||||
|         bool contains_x(expr* e) { | ||||
|             return (*m_var)(e); | ||||
|         } | ||||
| 
 | ||||
|         void mk_eq(indices& x, indices y, expr_ref_vector& lits) { | ||||
|             unsigned n = x.m_values.size(); | ||||
|             for (unsigned j = 0; j < n; ++j) { | ||||
|                 lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // check that x occurs only under selects or in disequalities.
 | ||||
|         bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) { | ||||
|             expr_mark mark; | ||||
|             ptr_vector<app> todo; | ||||
|             app* e; | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 e = to_app(lits[i]); | ||||
|                 if (is_diseq_x(e)) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (contains_x(e)) { | ||||
|                     todo.push_back(e); | ||||
|                 } | ||||
|             } | ||||
|             while (!todo.empty()) { | ||||
|                 e = todo.back(); | ||||
|                 todo.pop_back();                     | ||||
|                 if (mark.is_marked(e)) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 mark.mark(e); | ||||
|                 if (m_var->x() == e) { | ||||
|                     return false; | ||||
|                 } | ||||
|                 unsigned start = 0; | ||||
|                 if (a.is_select(e)) { | ||||
|                     if (e->get_arg(0) == m_var->x()) { | ||||
|                         start = 1; | ||||
|                         selects.push_back(e); | ||||
|                     }  | ||||
|                 } | ||||
|                 for (unsigned i = start; i < e->get_num_args(); ++i) { | ||||
|                     todo.push_back(to_app(e->get_arg(i))); | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void elim_diseqs(expr_ref_vector& lits) { | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 if (is_diseq_x(lits[i].get())) { | ||||
|                     project_plugin::erase(lits, i); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         bool is_update_x(app* e) { | ||||
|             do { | ||||
|                 if (m_var->x() == e) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 if (a.is_store(e) && contains_x(e->get_arg(0))) { | ||||
|                     for (unsigned i = 1; i < e->get_num_args(); ++i) { | ||||
|                         if (contains_x(e->get_arg(i))) { | ||||
|                             return false; | ||||
|                         } | ||||
|                     } | ||||
|                     e = to_app(e->get_arg(0)); | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
|             while (false); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool is_diseq_x(expr* e) { | ||||
|             expr *f, * s, *t; | ||||
|             if (m.is_not(e, f) && m.is_eq(f, s, t)) { | ||||
|                 if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true; | ||||
|                 if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             // find an equality to solve for.
 | ||||
|             expr* s, *t; | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 if (m.is_eq(lits[i].get(), s, t)) { | ||||
|                     vector<indices> idxs; | ||||
|                     expr_ref save(m), back(m); | ||||
|                     save = lits[i].get(); | ||||
|                     back = lits.back(); | ||||
|                     lits[i] = back; | ||||
|                     lits.pop_back(); | ||||
|                     unsigned sz = lits.size(); | ||||
|                     if (contains_x(s) && !contains_x(t) && is_app(s)) { | ||||
|                         if (solve(model, to_app(s), t, idxs, vars, lits)) { | ||||
|                             return true; | ||||
|                         } | ||||
|                     } | ||||
|                     else if (contains_x(t) && !contains_x(s) && is_app(t)) { | ||||
|                         if (solve(model, to_app(t), s, idxs, vars, lits)) { | ||||
|                             return true; | ||||
|                         } | ||||
|                     } | ||||
|                     // put back the equality literal.
 | ||||
|                     lits.resize(sz); | ||||
|                     lits.push_back(back); | ||||
|                     lits[i] = save; | ||||
|                 } | ||||
|                 // TBD: not distinct?
 | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool solve(model& model, app* s, expr* t, vector<indices>& idxs, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             SASSERT(contains_x(s)); | ||||
|             SASSERT(!contains_x(t)); | ||||
| 
 | ||||
|             if (s == m_var->x()) { | ||||
|                 expr_ref result(s, m); | ||||
|                 expr_ref_vector args(m); | ||||
|                 sort* range = get_array_range(m.get_sort(s)); | ||||
|                 for (unsigned i = 0; i < idxs.size(); ++i) { | ||||
|                     app_ref var(m); | ||||
|                     var = m.mk_fresh_const("value", range); | ||||
|                     vars.push_back(var); | ||||
|                     args.reset(); | ||||
|                     args.push_back(result); | ||||
|                     args.append(idxs[i].m_values.size(), idxs[i].m_vars); | ||||
|                     args.push_back(var); | ||||
|                     result = a.mk_store(args.size(), args.c_ptr()); | ||||
|                 } | ||||
|                 expr_safe_replace sub(m); | ||||
|                 sub.insert(s, result); | ||||
|                 for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                     sub(lits[i].get(), result); | ||||
|                     lits[i] = result; | ||||
|                 } | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             if (a.is_store(s)) { | ||||
|                 unsigned n = s->get_num_args()-2; | ||||
|                 indices idx(m, model, n, s->get_args()+1); | ||||
|                 for (unsigned i = 1; i < n; ++i) { | ||||
|                     if (contains_x(s->get_arg(i))) { | ||||
|                         return false; | ||||
|                     } | ||||
|                 }  | ||||
|                 unsigned i; | ||||
|                 expr_ref_vector args(m); | ||||
|                 switch (contains(idx, idxs, i)) { | ||||
|                 case l_true: | ||||
|                     mk_eq(idx, idxs[i], lits); | ||||
|                     return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits); | ||||
|                 case l_false: | ||||
|                     for (unsigned i = 0; i < idxs.size(); ++i) { | ||||
|                         expr_ref_vector eqs(m); | ||||
|                         mk_eq(idx, idxs[i], eqs); | ||||
|                         lits.push_back(m.mk_not(mk_and(eqs))); // TBD: extract single index of difference based on model.
 | ||||
|                     } | ||||
|                     args.push_back(t); | ||||
|                     args.append(n, s->get_args()+1); | ||||
|                     lits.push_back(m.mk_eq(a.mk_select(args.size(), args.c_ptr()), s->get_arg(n+1))); | ||||
|                     idxs.push_back(idx); | ||||
|                     return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits); | ||||
|                 case l_undef: | ||||
|                     return false; | ||||
|                 }                 | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         lbool contains(indices const& idx, vector<indices> const& idxs, unsigned& j) { | ||||
|             for (unsigned i = 0; i < idxs.size(); ++i) { | ||||
|                 switch (compare(idx, idxs[i])) { | ||||
|                 case l_true:  | ||||
|                     j = i; | ||||
|                     return l_true; | ||||
|                 case l_false: | ||||
|                     break; | ||||
|                 case l_undef: | ||||
|                     return l_undef;                 | ||||
|                 } | ||||
|             } | ||||
|             return l_false; | ||||
|         } | ||||
| 
 | ||||
|         lbool compare(indices const& idx1, indices const& idx2) { | ||||
|             unsigned n = idx1.m_values.size(); | ||||
|             for (unsigned i = 0; i < n; ++i) { | ||||
|                 switch (compare(idx1.m_values[i], idx2.m_values[i])) { | ||||
|                 case l_true: | ||||
|                     break; | ||||
|                 case l_false: | ||||
|                     return l_false; | ||||
|                 case l_undef: | ||||
|                     return l_undef; | ||||
|                 } | ||||
|             } | ||||
|             return l_true; | ||||
|         } | ||||
| 
 | ||||
|         lbool compare(expr* val1, expr* val2) { | ||||
|             if (val1 == val2) { | ||||
|                 return l_true; | ||||
|             } | ||||
|             if (is_uninterp(val1) || | ||||
|                 is_uninterp(val2)) { | ||||
|                 // TBD chase definition of nested array.
 | ||||
|                 return l_undef; | ||||
|             } | ||||
|             return l_true; | ||||
|         }             | ||||
|     }; | ||||
|      | ||||
|      | ||||
|     array_project_plugin::array_project_plugin(ast_manager& m) { | ||||
|         m_imp = alloc(imp, m); | ||||
|     } | ||||
|      | ||||
|     array_project_plugin::~array_project_plugin() { | ||||
|         dealloc(m_imp); | ||||
|     } | ||||
|      | ||||
|     bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|         return (*m_imp)(model, var, vars, lits); | ||||
|     } | ||||
| 
 | ||||
|     bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|         return m_imp->solve(model, vars, lits); | ||||
|     } | ||||
|      | ||||
|     family_id array_project_plugin::get_family_id() { | ||||
|         return m_imp->a.get_family_id(); | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										42
									
								
								src/qe/qe_arrays.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/qe/qe_arrays.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qe_arrays.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Model based projection for arrays | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-06-13 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| 
 | ||||
| #ifndef __QE_ARRAYS_H_ | ||||
| #define __QE_ARRAYS_H_ | ||||
| 
 | ||||
| #include "array_decl_plugin.h" | ||||
| #include "qe_mbp.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     class array_project_plugin : public project_plugin { | ||||
|         struct imp; | ||||
|         imp* m_imp; | ||||
|     public: | ||||
|         array_project_plugin(ast_manager& m); | ||||
|         virtual ~array_project_plugin(); | ||||
|         virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); | ||||
|         virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); | ||||
|         virtual family_id get_family_id(); | ||||
|     }; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										312
									
								
								src/qe/qe_datatypes.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										312
									
								
								src/qe/qe_datatypes.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,312 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qe_datatypes.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Simple projection function for algebraic datatypes. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-06-13 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #include "qe_arith.h" | ||||
| #include "ast_pp.h" | ||||
| #include "th_rewriter.h" | ||||
| #include "expr_functors.h" | ||||
| #include "model_v2_pp.h" | ||||
| #include "expr_safe_replace.h" | ||||
| #include "obj_pair_hashtable.h" | ||||
| #include "qe_datatypes.h" | ||||
| 
 | ||||
| namespace qe { | ||||
|      | ||||
|     struct datatype_project_plugin::imp  { | ||||
|         ast_manager&              m; | ||||
|         datatype_util             dt; | ||||
|         app_ref                   m_val; | ||||
|         scoped_ptr<contains_app>  m_var; | ||||
|          | ||||
|         imp(ast_manager& m): | ||||
|             m(m), dt(m), m_val(m) {} | ||||
|          | ||||
|         virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             return lift_foreign(vars, lits); | ||||
|         } | ||||
| 
 | ||||
|         bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             expr_ref val(m); | ||||
|             VERIFY(model.eval(var, val)); | ||||
|             SASSERT(is_app(val)); | ||||
|             TRACE("qe", tout << mk_pp(var, m) << " := " << val << "\n";); | ||||
|             m_val = to_app(val); | ||||
|             if (!dt.is_constructor(m_val)) { | ||||
|                 // assert: var does not occur in lits.
 | ||||
|                 return true; | ||||
|             } | ||||
|             m_var = alloc(contains_app, m, var); | ||||
| 
 | ||||
| 
 | ||||
|             try { | ||||
|                 if (dt.is_recursive(m.get_sort(var))) { | ||||
|                     project_rec(model, vars, lits); | ||||
|                 } | ||||
|                 else { | ||||
|                     project_nonrec(model, vars, lits); | ||||
|                 } | ||||
|             } | ||||
|             catch (cant_project) { | ||||
|                 TRACE("qe", tout << "can't project:" << mk_pp(var, m) << "\n";); | ||||
|                 return false; | ||||
|             } | ||||
|             return true; | ||||
|         }         | ||||
|      | ||||
|         void project_nonrec(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             expr_ref tmp(m), val(m); | ||||
|             expr_ref_vector args(m); | ||||
|             app_ref arg(m); | ||||
|             SASSERT(dt.is_constructor(m_val)); | ||||
|             func_decl* f = m_val->get_decl(); | ||||
|             ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f); | ||||
|             for (unsigned i = 0; i < acc.size(); ++i) { | ||||
|                 arg = m.mk_fresh_const(acc[i]->get_name().str().c_str(), acc[i]->get_range()); | ||||
|                 model.register_decl(arg->get_decl(), m_val->get_arg(i)); | ||||
|                 args.push_back(arg); | ||||
|             } | ||||
|             val = m.mk_app(f, args.size(), args.c_ptr()); | ||||
|             TRACE("qe", tout << mk_pp(m_var->x(), m) << " |-> " << val << "\n";); | ||||
|             reduce(val, lits); | ||||
|         } | ||||
| 
 | ||||
|         void project_rec(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             func_decl* f = m_val->get_decl(); | ||||
|             expr_ref rhs(m); | ||||
|             expr_ref_vector eqs(m); | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 if (solve(model, vars, lits[i].get(), rhs, eqs)) { | ||||
|                     project_plugin::erase(lits, i); | ||||
|                     reduce(rhs, lits); | ||||
|                     lits.append(eqs); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // otherwise, unfold the constructor associated with m_var
 | ||||
|             // once according to the model. In this way, selector-constructor
 | ||||
|             // redexes are reduced and disequalities are eventually solved
 | ||||
|             // by virtue of the constructors being different.
 | ||||
|             project_nonrec(model, vars, lits); | ||||
|         } | ||||
| 
 | ||||
|         void reduce(expr* val, expr_ref_vector& lits) { | ||||
|             expr_safe_replace sub(m); | ||||
|             th_rewriter rw(m); | ||||
|             expr_ref tmp(m); | ||||
|             sub.insert(m_var->x(), val); | ||||
|             TRACE("qe", tout << mk_pp(m_var->x(), m) << " = " << mk_pp(val, m) << "\n"; | ||||
|                   tout << lits << "\n";); | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) {                 | ||||
|                 sub(lits[i].get(), tmp); | ||||
|                 rw(tmp); | ||||
|                 lits[i] = tmp; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         bool contains_x(expr* e) { | ||||
|             return (*m_var)(e); | ||||
|         } | ||||
| 
 | ||||
|         bool solve(model& model, app_ref_vector& vars, expr* fml, expr_ref& t, expr_ref_vector& eqs) { | ||||
|             expr* t1, *t2; | ||||
|             if (m.is_eq(fml, t1, t2)) { | ||||
|                 if (contains_x(t1) && !contains_x(t2) && is_app(t1)) { | ||||
|                     return solve(model, vars, to_app(t1), t2, t, eqs); | ||||
|                 } | ||||
|                 if (contains_x(t2) && !contains_x(t1) && is_app(t2)) { | ||||
|                     return solve(model, vars, to_app(t2), t1, t, eqs); | ||||
|                 } | ||||
|             } | ||||
|             if (m.is_not(fml, t1) && m.is_distinct(t1)) { | ||||
|                 expr_ref eq = project_plugin::pick_equality(m, model, t1); | ||||
|                 return solve(model, vars, eq, t, eqs); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool solve(model& model, app_ref_vector& vars, app* a, expr* b, expr_ref& t, expr_ref_vector& eqs) { | ||||
|             SASSERT(contains_x(a)); | ||||
|             SASSERT(!contains_x(b)); | ||||
|             if (m_var->x() == a) { | ||||
|                 t = b; | ||||
|                 return true; | ||||
|             } | ||||
|             if (!dt.is_constructor(a)) { | ||||
|                 return false; | ||||
|             } | ||||
|             func_decl* c = a->get_decl(); | ||||
|             func_decl* rec = dt.get_constructor_recognizer(c); | ||||
|             ptr_vector<func_decl> const & acc = *dt.get_constructor_accessors(c); | ||||
|             SASSERT(acc.size() == a->get_num_args()); | ||||
|             //
 | ||||
|             // It suffices to solve just the first available equality.
 | ||||
|             // The others are determined by the first.
 | ||||
|             //
 | ||||
|             for (unsigned i = 0; i < a->get_num_args(); ++i) { | ||||
|                 expr* l = a->get_arg(i); | ||||
|                 if (is_app(l) && contains_x(l)) { | ||||
|                     expr_ref r(m); | ||||
|                     r = access(c, i, acc, b); | ||||
|                     if (solve(model, vars, to_app(l), r, t, eqs)) { | ||||
|                         for (unsigned j = 0; j < c->get_arity(); ++j) { | ||||
|                             if (i != j) { | ||||
|                                 eqs.push_back(m.mk_eq(access(c, j, acc, b), a->get_arg(j))); | ||||
|                             } | ||||
|                         } | ||||
|                         if (!is_app_of(b, c)) { | ||||
|                             eqs.push_back(m.mk_app(rec, b)); | ||||
|                         } | ||||
| 
 | ||||
|                         return true; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         expr* access(func_decl* c, unsigned i, ptr_vector<func_decl> const& acc, expr* e) { | ||||
|             if (is_app_of(e,c)) { | ||||
|                 return to_app(e)->get_arg(i); | ||||
|             } | ||||
|             else { | ||||
|                 return m.mk_app(acc[i], e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         bool lift_foreign(app_ref_vector const& vars, expr_ref_vector& lits) { | ||||
| 
 | ||||
|             bool reduced = false; | ||||
|             expr_mark visited; | ||||
|             expr_mark has_var; | ||||
|             bool inserted = false; | ||||
|             for (unsigned i = 0; i < vars.size(); ++i) {  | ||||
|                 if (m.is_bool(vars[i])) continue; | ||||
|                 if (dt.is_datatype(m.get_sort(vars[i]))) continue; | ||||
|                 inserted = true; | ||||
|                 has_var.mark(vars[i]); | ||||
|                 visited.mark(vars[i]); | ||||
|             } | ||||
|             if (inserted) { | ||||
|                 for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                     expr* e = lits[i].get(), *l, *r; | ||||
|                     if (m.is_eq(e, l, r) && reduce_eq(visited, has_var, l, r, lits)) { | ||||
|                         project_plugin::erase(lits, i); | ||||
|                         reduced = true; | ||||
|                     } | ||||
|                 } | ||||
|                 CTRACE("qe", reduced, tout << vars << "\n" << lits << "\n";); | ||||
|             } | ||||
|             return reduced; | ||||
|         } | ||||
| 
 | ||||
|         bool reduce_eq(expr_mark& has_var, expr_mark& visited, expr* l, expr* r, expr_ref_vector& lits) { | ||||
|             if (!is_app(l) || !is_app(r)) { | ||||
|                 return false; | ||||
|             } | ||||
|             bool reduce = false; | ||||
|             if (dt.is_constructor(to_app(r)) && contains_foreign(has_var, visited, r)) { | ||||
|                 std::swap(l, r); | ||||
|                 reduce = true; | ||||
|             } | ||||
|             reduce |= dt.is_constructor(to_app(l)) && contains_foreign(has_var, visited, l); | ||||
|             if (!reduce) { | ||||
|                 return false; | ||||
|             } | ||||
|             func_decl* c = to_app(l)->get_decl(); | ||||
|             ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(c); | ||||
|             if (!is_app_of(r, c)) { | ||||
|                 lits.push_back(m.mk_app(dt.get_constructor_recognizer(c), r)); | ||||
|             } | ||||
|             for (unsigned i = 0; i < acc.size(); ++i) { | ||||
|                 lits.push_back(m.mk_eq(to_app(l)->get_arg(i), access(c, i, acc, r))); | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         ptr_vector<expr> todo; | ||||
| 
 | ||||
|         bool contains_foreign(expr_mark& has_var, expr_mark& visited, expr* e) { | ||||
|             todo.push_back(e); | ||||
|             while (!todo.empty()) { | ||||
|                 expr* _f = todo.back(); | ||||
|                 if (visited.is_marked(_f)) { | ||||
|                     todo.pop_back(); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (!is_app(_f)) { | ||||
|                     visited.mark(_f);                    | ||||
|                     todo.pop_back(); | ||||
|                     continue; | ||||
|                 } | ||||
|                 app* f = to_app(_f); | ||||
|                 bool has_new = false, has_v = false; | ||||
|                 for (unsigned i = 0; i < f->get_num_args(); ++i) { | ||||
|                     expr* arg = f->get_arg(i); | ||||
|                     if (!visited.is_marked(arg)) { | ||||
|                         todo.push_back(arg); | ||||
|                         has_new = true; | ||||
|                     } | ||||
|                     else { | ||||
|                         has_v |= has_var.is_marked(arg); | ||||
|                     } | ||||
|                 } | ||||
|                 if (has_new) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 todo.pop_back(); | ||||
|                 if (has_v) { | ||||
|                     has_var.mark(f); | ||||
|                 } | ||||
|                 TRACE("qe", tout << "contains: " << mk_pp(f, m) << " " << has_var.is_marked(f) << "\n";); | ||||
|                 visited.mark(f); | ||||
|             } | ||||
|             TRACE("qe", tout << "contains: " << mk_pp(e, m) << " " << has_var.is_marked(e) << "\n";); | ||||
|             return has_var.is_marked(e); | ||||
|         } | ||||
|          | ||||
|     }; | ||||
|      | ||||
|     datatype_project_plugin::datatype_project_plugin(ast_manager& m) { | ||||
|         m_imp = alloc(imp, m); | ||||
|     } | ||||
|      | ||||
|     datatype_project_plugin::~datatype_project_plugin() { | ||||
|         dealloc(m_imp); | ||||
|     } | ||||
|      | ||||
|     bool datatype_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|         return (*m_imp)(model, var, vars, lits); | ||||
|     } | ||||
| 
 | ||||
|     bool datatype_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|         return m_imp->solve(model, vars, lits); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     family_id datatype_project_plugin::get_family_id() { | ||||
|         return m_imp->dt.get_family_id(); | ||||
|     } | ||||
|      | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										42
									
								
								src/qe/qe_datatypes.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/qe/qe_datatypes.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qe_datatypes.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Model based projection for algebraic datatypes | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-06-13 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| 
 | ||||
| #ifndef __QE_DATATYPES_H_ | ||||
| #define __QE_DATATYPES_H_ | ||||
| 
 | ||||
| #include "datatype_decl_plugin.h" | ||||
| #include "qe_mbp.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     class datatype_project_plugin : public project_plugin { | ||||
|         struct imp; | ||||
|         imp* m_imp; | ||||
|     public: | ||||
|         datatype_project_plugin(ast_manager& m); | ||||
|         virtual ~datatype_project_plugin(); | ||||
|         virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); | ||||
|         virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); | ||||
|         virtual family_id get_family_id(); | ||||
|     }; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -31,7 +31,6 @@ Revision History: | |||
| #include "var_subst.h" | ||||
| #include "uint_set.h" | ||||
| #include "ast_util.h" | ||||
| #include "qe_util.h" | ||||
| #include "th_rewriter.h" | ||||
| #include "for_each_expr.h" | ||||
| #include "expr_safe_replace.h" | ||||
|  |  | |||
							
								
								
									
										369
									
								
								src/qe/qe_mbp.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										369
									
								
								src/qe/qe_mbp.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,369 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qe_mbp.cpp | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Model-based projection utilities | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-5-29 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #include "qe_mbp.h" | ||||
| #include "qe_arith.h" | ||||
| #include "qe_arrays.h" | ||||
| #include "qe_datatypes.h" | ||||
| #include "expr_safe_replace.h" | ||||
| #include "ast_pp.h" | ||||
| #include "ast_util.h" | ||||
| #include "th_rewriter.h" | ||||
| #include "model_v2_pp.h" | ||||
| #include "expr_functors.h" | ||||
| 
 | ||||
| 
 | ||||
| using namespace qe; | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|    \brief return two terms that are equal in the model. | ||||
|    The distinct term t is false in model, so there  | ||||
|    are at least two arguments of t that are equal in the model. | ||||
| */ | ||||
| expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) { | ||||
|     SASSERT(m.is_distinct(t)); | ||||
|     expr_ref val(m); | ||||
|     expr_ref_vector vals(m); | ||||
|     obj_map<expr, expr*> val2expr; | ||||
|     app* alit = to_app(t); | ||||
|     for (unsigned i = 0; i < alit->get_num_args(); ++i) { | ||||
|         expr* e1 = alit->get_arg(i), *e2; | ||||
|         VERIFY(model.eval(e1, val)); | ||||
|         if (val2expr.find(val, e2)) { | ||||
|             return expr_ref(m.mk_eq(e1, e2), m); | ||||
|         } | ||||
|         val2expr.insert(val, e1); | ||||
|         vals.push_back(val); | ||||
|     } | ||||
|     UNREACHABLE(); | ||||
|     return expr_ref(0, m); | ||||
| } | ||||
| 
 | ||||
| void project_plugin::partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits) { | ||||
|     ast_manager& m = vals.get_manager(); | ||||
|     expr_ref val(m); | ||||
|     expr_ref_vector trail(m), reps(m); | ||||
|     obj_map<expr, expr*> roots; | ||||
|     for (unsigned i = 0; i < vals.size(); ++i) { | ||||
|         expr* v = vals[i], *root; | ||||
|         VERIFY (model.eval(v, val)); | ||||
|         if (roots.find(val, root)) { | ||||
|             lits.push_back(m.mk_eq(v, root)); | ||||
|         } | ||||
|         else { | ||||
|             roots.insert(val, v); | ||||
|             trail.push_back(val); | ||||
|             reps.push_back(v); | ||||
|         } | ||||
|     } | ||||
|     if (reps.size() > 1) {                 | ||||
|         lits.push_back(mk_distinct(reps)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) { | ||||
|     ast_manager& m = selects.get_manager(); | ||||
|     if (selects.empty()) return; | ||||
|     unsigned num_args = selects[0]->get_decl()->get_arity(); | ||||
|     for (unsigned j = 1; j < num_args; ++j) { | ||||
|         expr_ref_vector args(m);             | ||||
|         for (unsigned i = 0; i < selects.size(); ++i) { | ||||
|             args.push_back(selects[i]->get_arg(j)); | ||||
|         } | ||||
|         project_plugin::partition_values(model, args, lits); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void project_plugin::erase(expr_ref_vector& lits, unsigned& i) { | ||||
|     lits[i] = lits.back(); | ||||
|     lits.pop_back(); | ||||
|     --i; | ||||
| } | ||||
| 
 | ||||
| void project_plugin::push_back(expr_ref_vector& lits, expr* e) { | ||||
|     if (lits.get_manager().is_true(e)) return; | ||||
|     lits.push_back(e); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class mbp::impl { | ||||
|     ast_manager& m; | ||||
|     ptr_vector<project_plugin> m_plugins; | ||||
| 
 | ||||
|     void add_plugin(project_plugin* p) { | ||||
|         family_id fid = p->get_family_id(); | ||||
|         SASSERT(!m_plugins.get(fid, 0)); | ||||
|         m_plugins.setx(fid, p, 0); | ||||
|     } | ||||
| 
 | ||||
|     project_plugin* get_plugin(app* var) { | ||||
|         family_id fid = m.get_sort(var)->get_family_id(); | ||||
|         return m_plugins.get(fid, 0); | ||||
|     } | ||||
| 
 | ||||
|     bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|         expr_mark is_var, is_rem; | ||||
|         if (vars.empty()) { | ||||
|             return false; | ||||
|         } | ||||
|         bool reduced = false; | ||||
|         for (unsigned i = 0; i < vars.size(); ++i) {  | ||||
|             is_var.mark(vars[i].get()); | ||||
|         } | ||||
|         expr_ref tmp(m), t(m), v(m);             | ||||
|         th_rewriter rw(m); | ||||
|         for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|             expr* e = lits[i].get(), *l, *r; | ||||
|             if (m.is_eq(e, l, r) && reduce_eq(is_var, l, r, v, t)) { | ||||
|                 reduced = true; | ||||
|                 lits[i] = lits.back(); | ||||
|                 lits.pop_back(); | ||||
|                 --i; | ||||
|                 expr_safe_replace sub(m); | ||||
|                 sub.insert(v, t); | ||||
|                 is_rem.mark(v); | ||||
|                 for (unsigned j = 0; j < lits.size(); ++j) { | ||||
|                     sub(lits[j].get(), tmp); | ||||
|                     rw(tmp); | ||||
|                     lits[j] = tmp; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (reduced) { | ||||
|             for (unsigned i = 0; i < vars.size(); ++i) { | ||||
|                 if (is_rem.is_marked(vars[i].get())) { | ||||
|                     vars[i] = vars.back(); | ||||
|                     vars.pop_back(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return reduced; | ||||
|     } | ||||
| 
 | ||||
|     bool reduce_eq(expr_mark& is_var, expr* l, expr* r, expr_ref& v, expr_ref& t) { | ||||
|         if (is_var.is_marked(r)) { | ||||
|             std::swap(l, r); | ||||
|         } | ||||
|         if (is_var.is_marked(l)) { | ||||
|             contains_app cont(m, to_app(l)); | ||||
|             if (!cont(r)) { | ||||
|                 v = to_app(l); | ||||
|                 t = r; | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     void extract_literals(model& model, expr_ref_vector& fmls) { | ||||
|         expr_ref val(m); | ||||
|         for (unsigned i = 0; i < fmls.size(); ++i) { | ||||
|             expr* fml = fmls[i].get(), *nfml, *f1, *f2, *f3; | ||||
|             if (m.is_not(fml, nfml) && m.is_distinct(nfml)) { | ||||
|                 fmls[i] = project_plugin::pick_equality(m, model, nfml); | ||||
|                 --i; | ||||
|             } | ||||
|             else if (m.is_or(fml)) { | ||||
|                 for (unsigned j = 0; j < to_app(fml)->get_num_args(); ++j) { | ||||
|                     VERIFY (model.eval(to_app(fml)->get_arg(j), val)); | ||||
|                     if (m.is_true(val)) { | ||||
|                         fmls[i] = to_app(fml)->get_arg(j); | ||||
|                         --i; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             else if (m.is_and(fml)) { | ||||
|                 fmls.append(to_app(fml)->get_num_args(), to_app(fml)->get_args()); | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else if (m.is_iff(fml, f1, f2) || (m.is_not(fml, nfml) && m.is_xor(nfml, f1, f2))) { | ||||
|                 VERIFY (model.eval(f1, val)); | ||||
|                 if (m.is_false(val)) { | ||||
|                     f1 = mk_not(m, f1); | ||||
|                     f2 = mk_not(m, f2); | ||||
|                 } | ||||
|                 project_plugin::push_back(fmls, f1); | ||||
|                 project_plugin::push_back(fmls, f2); | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else if (m.is_implies(fml, f1, f2)) { | ||||
|                 VERIFY (model.eval(f2, val)); | ||||
|                 if (m.is_true(val)) { | ||||
|                     project_plugin::push_back(fmls, f2); | ||||
|                 } | ||||
|                 else { | ||||
|                     project_plugin::push_back(fmls, mk_not(m, f1)); | ||||
|                 } | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else if (m.is_ite(fml, f1, f2, f3)) { | ||||
|                 VERIFY (model.eval(f1, val));                 | ||||
|                 if (m.is_true(val)) { | ||||
|                     project_plugin::push_back(fmls, f2); | ||||
|                 } | ||||
|                 else { | ||||
|                     project_plugin::push_back(fmls, f3); | ||||
|                 } | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else if (m.is_not(fml, nfml) && m.is_not(nfml, nfml)) { | ||||
|                 project_plugin::push_back(fmls, nfml); | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else if (m.is_not(fml, nfml) && m.is_and(nfml)) { | ||||
|                 for (unsigned j = 0; j < to_app(nfml)->get_num_args(); ++j) { | ||||
|                     VERIFY (model.eval(to_app(nfml)->get_arg(j), val)); | ||||
|                     if (m.is_false(val)) { | ||||
|                         fmls[i] = mk_not(m, to_app(nfml)->get_arg(j)); | ||||
|                         --i; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             else if (m.is_not(fml, nfml) && m.is_or(nfml)) { | ||||
|                 for (unsigned j = 0; j < to_app(nfml)->get_num_args(); ++j) { | ||||
|                     project_plugin::push_back(fmls, mk_not(m, to_app(nfml)->get_arg(j))); | ||||
|                 } | ||||
|                 project_plugin::erase(fmls, i);                 | ||||
|             } | ||||
|             else if ((m.is_not(fml, nfml) && m.is_iff(nfml, f1, f2)) || m.is_xor(fml, f1, f2)) { | ||||
|                 VERIFY (model.eval(f1, val)); | ||||
|                 if (m.is_true(val)) { | ||||
|                     f2 = mk_not(m, f2); | ||||
|                 } | ||||
|                 else { | ||||
|                     f1 = mk_not(m, f1); | ||||
|                 } | ||||
|                 project_plugin::push_back(fmls, f1); | ||||
|                 project_plugin::push_back(fmls, f2); | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else if (m.is_not(fml, nfml) && m.is_implies(nfml, f1, f2)) { | ||||
|                 project_plugin::push_back(fmls, f1); | ||||
|                 project_plugin::push_back(fmls, mk_not(m, f2)); | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else if (m.is_not(fml, nfml) && m.is_ite(nfml, f1, f2, f3)) { | ||||
|                 VERIFY (model.eval(f1, val));                 | ||||
|                 if (m.is_true(val)) { | ||||
|                     project_plugin::push_back(fmls, mk_not(m, f2)); | ||||
|                 } | ||||
|                 else { | ||||
|                     project_plugin::push_back(fmls, mk_not(m, f3)); | ||||
|                 } | ||||
|                 project_plugin::erase(fmls, i); | ||||
|             } | ||||
|             else { | ||||
|                 // TBD other Boolean operations.
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl(ast_manager& m):m(m) { | ||||
|         add_plugin(alloc(arith_project_plugin, m)); | ||||
|         add_plugin(alloc(datatype_project_plugin, m)); | ||||
|         add_plugin(alloc(array_project_plugin, m)); | ||||
|     } | ||||
| 
 | ||||
|     ~impl() { | ||||
|         std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc<project_plugin>()); | ||||
|     } | ||||
| 
 | ||||
|     void preprocess_solve(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { | ||||
|         extract_literals(model, fmls); | ||||
|         bool change = true; | ||||
|         while (change && !vars.empty()) { | ||||
|             change = solve(model, vars, fmls); | ||||
|             for (unsigned i = 0; i < m_plugins.size(); ++i) { | ||||
|                 if (m_plugins[i] && m_plugins[i]->solve(model, vars, fmls)) { | ||||
|                     change = true; | ||||
|                 } | ||||
|             } | ||||
|         }         | ||||
|     } | ||||
| 
 | ||||
|     void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) { | ||||
|         expr_ref val(m), tmp(m); | ||||
|         app_ref var(m); | ||||
|         th_rewriter rw(m); | ||||
|         bool progress = true; | ||||
|         while (progress && !vars.empty()) { | ||||
|             preprocess_solve(model, vars, fmls); | ||||
|             app_ref_vector new_vars(m); | ||||
|             progress = false; | ||||
|             while (!vars.empty()) { | ||||
|                 var = vars.back(); | ||||
|                 vars.pop_back(); | ||||
|                 project_plugin* p = get_plugin(var); | ||||
|                 if (p && (*p)(model, var, vars, fmls)) { | ||||
|                     progress = true; | ||||
|                 } | ||||
|                 else { | ||||
|                     new_vars.push_back(var); | ||||
|                 } | ||||
|             } | ||||
|             if (!progress && !new_vars.empty() && force_elim) { | ||||
|                 var = new_vars.back(); | ||||
|                 new_vars.pop_back(); | ||||
|                 expr_safe_replace sub(m); | ||||
|                 VERIFY(model.eval(var, val)); | ||||
|                 sub.insert(var, val); | ||||
|                 for (unsigned i = 0; i < fmls.size(); ++i) { | ||||
|                     sub(fmls[i].get(), tmp); | ||||
|                     rw(tmp); | ||||
|                     if (m.is_true(tmp)) { | ||||
|                         fmls[i] = fmls.back(); | ||||
|                         fmls.pop_back(); | ||||
|                         --i; | ||||
|                     } | ||||
|                     else { | ||||
|                         fmls[i] = tmp; | ||||
|                     } | ||||
|                 }             | ||||
|                 progress = true; | ||||
|             } | ||||
|             vars.append(new_vars); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|      | ||||
| mbp::mbp(ast_manager& m) { | ||||
|     m_impl = alloc(impl, m); | ||||
| } | ||||
|          | ||||
| mbp::~mbp() { | ||||
|     dealloc(m_impl); | ||||
| } | ||||
|          | ||||
| void mbp::operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls) { | ||||
|     (*m_impl)(force_elim, vars, mdl, fmls); | ||||
| } | ||||
| 
 | ||||
| void mbp::solve(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { | ||||
|     m_impl->preprocess_solve(model, vars, fmls); | ||||
| } | ||||
|          | ||||
| void mbp::extract_literals(model& model, expr_ref_vector& lits) { | ||||
|     m_impl->extract_literals(model, lits); | ||||
| } | ||||
							
								
								
									
										76
									
								
								src/qe/qe_mbp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/qe/qe_mbp.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qe_mbp.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Model-based projection utilities | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-5-28 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #ifndef __QE_MBP_H__ | ||||
| #define __QE_MBP_H__ | ||||
| 
 | ||||
| #include "ast.h" | ||||
| #include "params.h" | ||||
| #include "model.h" | ||||
| 
 | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     struct cant_project {}; | ||||
| 
 | ||||
|     class project_plugin { | ||||
|     public: | ||||
|         virtual ~project_plugin() {} | ||||
|         virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) = 0; | ||||
|         virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) = 0; | ||||
|         virtual family_id get_family_id() = 0; | ||||
| 
 | ||||
|         static expr_ref pick_equality(ast_manager& m, model& model, expr* t); | ||||
|         static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); | ||||
|         static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); | ||||
|         static void erase(expr_ref_vector& lits, unsigned& i); | ||||
|         static void push_back(expr_ref_vector& lits, expr* lit); | ||||
|     }; | ||||
| 
 | ||||
|     class mbp { | ||||
|         class impl; | ||||
|         impl * m_impl; | ||||
|     public: | ||||
|         mbp(ast_manager& m); | ||||
|          | ||||
|         ~mbp(); | ||||
|          | ||||
|         /**
 | ||||
|            \brief | ||||
|            Apply model-based qe on constants provided as vector of variables.  | ||||
|            Return the updated formula and updated set of variables that were not eliminated.            | ||||
|         */ | ||||
|         void operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief | ||||
|            Solve as many variables as possible using "cheap" quantifier elimination" | ||||
|         */ | ||||
|         void solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief  | ||||
|            Extract literals from formulas based on model. | ||||
|          */ | ||||
|         void extract_literals(model& model, expr_ref_vector& lits); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif  | ||||
|  | @ -22,6 +22,7 @@ Revision History: | |||
| #include"qe.h" | ||||
| 
 | ||||
| class qe_tactic : public tactic { | ||||
|     statistics               m_st; | ||||
|     struct     imp { | ||||
|         ast_manager &            m; | ||||
|         smt_params               m_fparams; | ||||
|  | @ -78,10 +79,19 @@ class qe_tactic : public tactic { | |||
|                 g->update(i, new_f, new_pr, g->dep(i));                 | ||||
|             } | ||||
|             g->inc_depth(); | ||||
|             g->elim_true(); | ||||
|             result.push_back(g.get()); | ||||
|             TRACE("qe", g->display(tout);); | ||||
|             SASSERT(g->is_well_sorted()); | ||||
|         } | ||||
| 
 | ||||
|         void collect_statistics(statistics & st) const { | ||||
|             m_qe.collect_statistics(st); | ||||
|         } | ||||
| 
 | ||||
|         void reset_statistics() {             | ||||
|         } | ||||
| 
 | ||||
|     }; | ||||
|      | ||||
|     imp *      m_imp; | ||||
|  | @ -117,7 +127,19 @@ public: | |||
|                             proof_converter_ref & pc, | ||||
|                             expr_dependency_ref & core) { | ||||
|         (*m_imp)(in, result, mc, pc, core); | ||||
|         m_st.reset(); | ||||
|         m_imp->collect_statistics(m_st); | ||||
|          | ||||
|     } | ||||
| 
 | ||||
|     virtual void collect_statistics(statistics & st) const { | ||||
|         st.copy(m_st); | ||||
|     } | ||||
| 
 | ||||
|     virtual void reset_statistics() { | ||||
|         m_st.reset(); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     virtual void cleanup() { | ||||
|         ast_manager & m = m_imp->m; | ||||
|  |  | |||
|  | @ -1,26 +0,0 @@ | |||
| 
 | ||||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #include "qe_util.h" | ||||
| #include "bool_rewriter.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     expr_ref mk_and(expr_ref_vector const& fmls) { | ||||
|         ast_manager& m = fmls.get_manager(); | ||||
|         expr_ref result(m); | ||||
|         bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), result); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     expr_ref mk_or(expr_ref_vector const& fmls) { | ||||
|         ast_manager& m = fmls.get_manager(); | ||||
|         expr_ref result(m); | ||||
|         bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), result); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,31 +0,0 @@ | |||
| /*++
 | ||||
| Copyright (c) 2013 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qe_util.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Utilities for quantifiers. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2013-08-28 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| --*/ | ||||
| #ifndef QE_UTIL_H_ | ||||
| #define QE_UTIL_H_ | ||||
| 
 | ||||
| #include "ast.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     expr_ref mk_and(expr_ref_vector const& fmls); | ||||
| 
 | ||||
|     expr_ref mk_or(expr_ref_vector const& fmls); | ||||
| 
 | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										1177
									
								
								src/qe/qsat.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1177
									
								
								src/qe/qsat.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										135
									
								
								src/qe/qsat.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/qe/qsat.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | |||
| /*++
 | ||||
| Copyright (c) 2015 Microsoft Corporation | ||||
| 
 | ||||
| Module Name: | ||||
| 
 | ||||
|     qsat.h | ||||
| 
 | ||||
| Abstract: | ||||
| 
 | ||||
|     Quantifier Satisfiability Solver. | ||||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     Nikolaj Bjorner (nbjorner) 2015-5-28 | ||||
| 
 | ||||
| Revision History: | ||||
| 
 | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
| #ifndef QE_QSAT_H__ | ||||
| #define QE_QSAT_H__ | ||||
| 
 | ||||
| #include "tactic.h" | ||||
| #include "filter_model_converter.h" | ||||
| 
 | ||||
| namespace qe { | ||||
| 
 | ||||
|     struct max_level { | ||||
|         unsigned m_ex, m_fa; | ||||
|         max_level(): m_ex(UINT_MAX), m_fa(UINT_MAX) {} | ||||
|         void merge(max_level const& other) { | ||||
|             merge(m_ex, other.m_ex); | ||||
|             merge(m_fa, other.m_fa); | ||||
|         } | ||||
|         static unsigned max(unsigned a, unsigned b) { | ||||
|             if (a == UINT_MAX) return b; | ||||
|             if (b == UINT_MAX) return a; | ||||
|             return std::max(a, b); | ||||
|         } | ||||
|         unsigned max() const { | ||||
|             return max(m_ex, m_fa); | ||||
|         } | ||||
|         void merge(unsigned& lvl, unsigned other) { | ||||
|             lvl = max(lvl, other); | ||||
|         } | ||||
|         std::ostream& display(std::ostream& out) const { | ||||
|             if (m_ex != UINT_MAX) out << "e" << m_ex << " "; | ||||
|             if (m_fa != UINT_MAX) out << "a" << m_fa << " "; | ||||
|             return out; | ||||
|         } | ||||
|          | ||||
|         bool operator==(max_level const& other) const { | ||||
|             return  | ||||
|                 m_ex == other.m_ex && | ||||
|                 m_fa == other.m_fa; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     inline std::ostream& operator<<(std::ostream& out, max_level const& lvl) { | ||||
|         return lvl.display(out); | ||||
|     } | ||||
| 
 | ||||
|     class pred_abs { | ||||
|         ast_manager&            m; | ||||
|         vector<app_ref_vector>  m_preds; | ||||
|         expr_ref_vector         m_asms; | ||||
|         unsigned_vector         m_asms_lim; | ||||
|         obj_map<expr, expr*>    m_pred2lit;    // maintain definitions of predicates.
 | ||||
|         obj_map<expr, app*>     m_lit2pred;    // maintain reverse mapping to predicates
 | ||||
|         obj_map<expr, app*>     m_asm2pred;    // maintain map from assumptions to predicates
 | ||||
|         obj_map<expr, expr*>    m_pred2asm;    // predicates |-> assumptions
 | ||||
|         expr_ref_vector         m_trail; | ||||
|         filter_model_converter_ref m_fmc; | ||||
|         ptr_vector<expr>        todo; | ||||
|         obj_map<expr, max_level>      m_elevel; | ||||
|         obj_map<func_decl, max_level> m_flevel; | ||||
| 
 | ||||
|         template <typename T> | ||||
|         void dec_keys(obj_map<expr, T*>& map) { | ||||
|             typename obj_map<expr, T*>::iterator it = map.begin(), end = map.end(); | ||||
|             for (; it != end; ++it) { | ||||
|                 m.dec_ref(it->m_key); | ||||
|             } | ||||
|         } | ||||
|         void add_lit(app* p, app* lit); | ||||
|         void add_asm(app* p, expr* lit);         | ||||
|         bool is_predicate(app* a, unsigned l); | ||||
|         void mk_concrete(expr_ref_vector& fmls, obj_map<expr, expr*> const& map); | ||||
|     public: | ||||
|          | ||||
|         pred_abs(ast_manager& m); | ||||
|         filter_model_converter* fmc(); | ||||
|         void reset(); | ||||
|         max_level compute_level(app* e); | ||||
|         void push(); | ||||
|         void pop(unsigned num_scopes); | ||||
|         void insert(app* a, max_level const& lvl); | ||||
|         void get_assumptions(model* mdl, expr_ref_vector& asms); | ||||
|         void set_expr_level(app* v, max_level const& lvl); | ||||
|         void set_decl_level(func_decl* v, max_level const& lvl); | ||||
|         void abstract_atoms(expr* fml, max_level& level, expr_ref_vector& defs); | ||||
|         void abstract_atoms(expr* fml, expr_ref_vector& defs); | ||||
|         expr_ref mk_abstract(expr* fml); | ||||
|         void pred2lit(expr_ref_vector& fmls); | ||||
|         expr_ref pred2asm(expr* fml); | ||||
|         void get_free_vars(expr* fml, app_ref_vector& vars); | ||||
|         expr_ref mk_assumption_literal(expr* a, model* mdl, max_level const& lvl, expr_ref_vector& defs); | ||||
|         void add_pred(app* p, app* lit); | ||||
|         app_ref fresh_bool(char const* name); | ||||
|         void display(std::ostream& out) const; | ||||
|         void display(std::ostream& out, expr_ref_vector const& asms) const; | ||||
|         void collect_statistics(statistics& st) const; | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| tactic * mk_qsat_tactic(ast_manager & m, params_ref const& p = params_ref()); | ||||
| 
 | ||||
| tactic * mk_qe2_tactic(ast_manager & m, params_ref const& p = params_ref()); | ||||
| 
 | ||||
| tactic * mk_qe_rec_tactic(ast_manager & m, params_ref const& p = params_ref()); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|   ADD_TACTIC("qsat", "apply a QSAT solver.", "mk_qsat_tactic(m, p)")  | ||||
| 
 | ||||
|   ADD_TACTIC("qe2", "apply a QSAT based quantifier elimination.", "mk_qe2_tactic(m, p)")  | ||||
| 
 | ||||
|   ADD_TACTIC("qe_rec", "apply a QSAT based quantifier elimination recursively.", "mk_qe_rec_tactic(m, p)")  | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| #endif  | ||||
|  | @ -257,8 +257,10 @@ public: | |||
|         if (m_preprocess) { | ||||
|             m_preprocess->reset(); | ||||
|         } | ||||
|         if (!m_bb_rewriter) { | ||||
|             m_bb_rewriter = alloc(bit_blaster_rewriter, m, m_params); | ||||
|         } | ||||
|         params_ref simp2_p = m_params; | ||||
|         m_bb_rewriter = alloc(bit_blaster_rewriter, m, m_params); | ||||
|         simp2_p.set_bool("som", true); | ||||
|         simp2_p.set_bool("pull_cheap_ite", true); | ||||
|         simp2_p.set_bool("push_ite_bv", false); | ||||
|  |  | |||
|  | @ -509,7 +509,7 @@ struct sat2goal::imp { | |||
|         // This information may be stored as a vector of pairs.
 | ||||
|         // The mapping is only created during the model conversion.
 | ||||
|         expr_ref_vector             m_var2expr; | ||||
|         ref<filter_model_converter> m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion
 | ||||
|         filter_model_converter_ref  m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion
 | ||||
|          | ||||
|         sat_model_converter(ast_manager & m): | ||||
|             m_var2expr(m) { | ||||
|  |  | |||
|  | @ -66,7 +66,7 @@ void display_usage() { | |||
| #ifdef Z3GITHASH | ||||
|     std::cout << " - build hashcode " << STRINGIZE_VALUE_OF(Z3GITHASH); | ||||
| #endif | ||||
|     std::cout << "]. (C) Copyright 2006-2014 Microsoft Corp.\n"; | ||||
|     std::cout << "]. (C) Copyright 2006-2016 Microsoft Corp.\n"; | ||||
|     std::cout << "Usage: z3 [options] [-file:]file\n"; | ||||
|     std::cout << "\nInput format:\n"; | ||||
|     std::cout << "  -smt        use parser for SMT input format.\n"; | ||||
|  |  | |||
|  | @ -797,13 +797,7 @@ MK_SIMPLIFIER(apply_bit2int, bit2int& functor = m_bit2int, "bit2int", "propagate | |||
| 
 | ||||
| MK_SIMPLIFIER(cheap_quant_fourier_motzkin, elim_bounds_star functor(m_manager), "elim_bounds", "cheap-fourier-motzkin", true); | ||||
| 
 | ||||
| // MK_SIMPLIFIER(quant_elim, qe::expr_quant_elim_star1 &functor = m_quant_elim, 
 | ||||
| //              "quantifiers", "quantifier elimination procedures", true);
 | ||||
| 
 | ||||
| bool asserted_formulas::quant_elim() { | ||||
|     throw default_exception("QUANT_ELIM option is deprecated, please consider using the 'qe' tactic."); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| MK_SIMPLIFIER(elim_bvs_from_quantifiers, bv_elim_star functor(m_manager), "bv_elim", "eliminate-bit-vectors-from-quantifiers", true); | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,7 +55,6 @@ class asserted_formulas { | |||
|     maximise_bv_sharing         m_bv_sharing; | ||||
| 
 | ||||
|     bool                        m_inconsistent; | ||||
|     // qe::expr_quant_elim_star1   m_quant_elim;
 | ||||
| 
 | ||||
|     struct scope { | ||||
|         unsigned                m_asserted_formulas_lim; | ||||
|  | @ -84,7 +83,6 @@ class asserted_formulas { | |||
|     void eliminate_and(); | ||||
|     void refine_inj_axiom(); | ||||
|     bool cheap_quant_fourier_motzkin(); | ||||
|     bool quant_elim(); | ||||
|     void apply_distribute_forall(); | ||||
|     bool apply_bit2int(); | ||||
|     void lift_ite(); | ||||
|  |  | |||
|  | @ -25,19 +25,17 @@ Revision History: | |||
| #include"well_sorted.h" | ||||
| #include"used_symbols.h" | ||||
| #include"model_v2_pp.h" | ||||
| #include"basic_simplifier_plugin.h" | ||||
| 
 | ||||
| proto_model::proto_model(ast_manager & m, simplifier & s, params_ref const & p): | ||||
| proto_model::proto_model(ast_manager & m, params_ref const & p): | ||||
|     model_core(m), | ||||
|     m_simplifier(s), | ||||
|     m_afid(m.mk_family_id(symbol("array"))), | ||||
|     m_eval(*this) { | ||||
|     m_eval(*this), | ||||
|     m_rewrite(m) { | ||||
|     register_factory(alloc(basic_factory, m)); | ||||
|     m_user_sort_factory = alloc(user_sort_factory, m); | ||||
|     register_factory(m_user_sort_factory); | ||||
|      | ||||
|     m_model_partial = model_params(p).partial(); | ||||
|     m_use_new_eval  = model_params(p).new_eval(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -85,61 +83,6 @@ expr * proto_model::mk_some_interp_for(func_decl * d) { | |||
|     return r; | ||||
| } | ||||
| 
 | ||||
| // Auxiliary function for computing fi(args[0], ..., args[fi.get_arity() - 1]).
 | ||||
| // The result is stored in result.
 | ||||
| // Return true if succeeded, and false otherwise.
 | ||||
| // It uses the simplifier s during the computation.
 | ||||
| bool eval(func_interp & fi, simplifier & s, expr * const * args, expr_ref & result) { | ||||
|     bool actuals_are_values = true; | ||||
|      | ||||
|     if (fi.num_entries() != 0) { | ||||
|         for (unsigned i = 0; actuals_are_values && i < fi.get_arity(); i++) { | ||||
|             actuals_are_values = fi.m().is_value(args[i]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     func_entry * entry = fi.get_entry(args); | ||||
|     if (entry != 0) { | ||||
|         result = entry->get_result(); | ||||
|         return true; | ||||
|     } | ||||
|      | ||||
|     TRACE("func_interp", tout << "failed to find entry for: ";  | ||||
|           for(unsigned i = 0; i < fi.get_arity(); i++)  | ||||
|              tout << mk_pp(args[i], fi.m()) << " ";  | ||||
|           tout << "\nis partial: " << fi.is_partial() << "\n";); | ||||
|      | ||||
|     if (!fi.eval_else(args, result)) { | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     if (actuals_are_values && fi.args_are_values()) { | ||||
|         // cheap case... we are done
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // build symbolic result... the actuals may be equal to the args of one of the entries.
 | ||||
|     basic_simplifier_plugin * bs = static_cast<basic_simplifier_plugin*>(s.get_plugin(fi.m().get_basic_family_id())); | ||||
|     for (unsigned k = 0; k < fi.num_entries(); k++) { | ||||
|         func_entry const * curr = fi.get_entry(k); | ||||
|         SASSERT(!curr->eq_args(fi.m(), fi.get_arity(), args)); | ||||
|         if (!actuals_are_values || !curr->args_are_values()) { | ||||
|             expr_ref_buffer eqs(fi.m()); | ||||
|             unsigned i = fi.get_arity(); | ||||
|             while (i > 0) { | ||||
|                 --i; | ||||
|                 expr_ref new_eq(fi.m()); | ||||
|                 bs->mk_eq(curr->get_arg(i), args[i], new_eq); | ||||
|                 eqs.push_back(new_eq); | ||||
|             } | ||||
|             SASSERT(eqs.size() == fi.get_arity()); | ||||
|             expr_ref new_cond(fi.m()); | ||||
|             bs->mk_and(eqs.size(), eqs.c_ptr(), new_cond); | ||||
|             bs->mk_ite(new_cond, curr->get_result(), result, result); | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool proto_model::is_select_of_model_value(expr* e) const { | ||||
|     return  | ||||
|  | @ -159,192 +102,16 @@ bool proto_model::is_select_of_model_value(expr* e) const { | |||
|    So, if model_completion == true, the evaluator never fails if it doesn't contain quantifiers. | ||||
| */ | ||||
| bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) { | ||||
|     if (m_use_new_eval) { | ||||
|         m_eval.set_model_completion(model_completion); | ||||
|         try { | ||||
|             m_eval(e, result); | ||||
|             return true; | ||||
|         } | ||||
|         catch (model_evaluator_exception & ex) { | ||||
|             (void)ex; | ||||
|             TRACE("model_evaluator", tout << ex.msg() << "\n";); | ||||
|             return false; | ||||
|         } | ||||
|     m_eval.set_model_completion(model_completion); | ||||
|     try { | ||||
|         m_eval(e, result); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool is_ok = true; | ||||
|     SASSERT(is_well_sorted(m_manager, e)); | ||||
|     TRACE("model_eval", tout << mk_pp(e, m_manager) << "\n"; | ||||
|           tout << "sort: " << mk_pp(m_manager.get_sort(e), m_manager) << "\n";); | ||||
|      | ||||
|     obj_map<expr, expr*> eval_cache; | ||||
|     expr_ref_vector trail(m_manager); | ||||
|     sbuffer<std::pair<expr*, expr*>, 128> todo; | ||||
|     ptr_buffer<expr> args; | ||||
|     expr * null = static_cast<expr*>(0); | ||||
|     todo.push_back(std::make_pair(e, null)); | ||||
|      | ||||
| 
 | ||||
|     expr * a; | ||||
|     expr * expanded_a; | ||||
|     while (!todo.empty()) { | ||||
|         std::pair<expr *, expr *> & p = todo.back(); | ||||
|         a          = p.first; | ||||
|         expanded_a = p.second; | ||||
|         if (expanded_a != 0) { | ||||
|             expr * r = 0; | ||||
|             eval_cache.find(expanded_a, r); | ||||
|             SASSERT(r != 0); | ||||
|             todo.pop_back(); | ||||
|             eval_cache.insert(a, r); | ||||
|             TRACE("model_eval",  | ||||
|                   tout << "orig:\n" << mk_pp(a, m_manager) << "\n"; | ||||
|                   tout << "after beta reduction:\n" << mk_pp(expanded_a, m_manager) << "\n"; | ||||
|                   tout << "new:\n" << mk_pp(r, m_manager) << "\n";); | ||||
|         } | ||||
|         else { | ||||
|             switch(a->get_kind()) { | ||||
|             case AST_APP: { | ||||
|                 app * t = to_app(a); | ||||
|                 bool visited = true; | ||||
|                 args.reset(); | ||||
|                 unsigned num_args = t->get_num_args(); | ||||
|                 for (unsigned i = 0; i < num_args; ++i) { | ||||
|                     expr * arg = 0; | ||||
|                     if (!eval_cache.find(t->get_arg(i), arg)) { | ||||
|                         visited = false; | ||||
|                         todo.push_back(std::make_pair(t->get_arg(i), null)); | ||||
|                     } | ||||
|                     else { | ||||
|                         args.push_back(arg); | ||||
|                     } | ||||
|                 } | ||||
|                 if (!visited) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 SASSERT(args.size() == t->get_num_args()); | ||||
|                 expr_ref new_t(m_manager); | ||||
|                 func_decl * f   = t->get_decl(); | ||||
|                  | ||||
|                 if (!has_interpretation(f)) { | ||||
|                     // the model does not assign an interpretation to f.
 | ||||
|                     SASSERT(new_t.get() == 0); | ||||
|                     if (f->get_family_id() == null_family_id) { | ||||
|                         if (model_completion) { | ||||
|                             // create an interpretation for f.
 | ||||
|                             new_t = mk_some_interp_for(f); | ||||
|                         } | ||||
|                         else { | ||||
|                             TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";); | ||||
|                             is_ok = false; | ||||
|                         } | ||||
|                     } | ||||
|                     if (new_t.get() == 0) { | ||||
|                         // t is interpreted or model completion is disabled.
 | ||||
|                         m_simplifier.mk_app(f, num_args, args.c_ptr(), new_t); | ||||
|                         TRACE("model_eval", tout << mk_pp(t, m_manager) << " -> " << new_t << "\n";); | ||||
|                         trail.push_back(new_t); | ||||
|                         if (!is_app(new_t) || to_app(new_t)->get_decl() != f || is_select_of_model_value(new_t)) { | ||||
|                             // if the result is not of the form (f ...), then assume we must simplify it.
 | ||||
|                             expr * new_new_t = 0; | ||||
|                             if (!eval_cache.find(new_t.get(), new_new_t)) { | ||||
|                                 todo.back().second = new_t; | ||||
|                                 todo.push_back(std::make_pair(new_t, null)); | ||||
|                                 continue; | ||||
|                             } | ||||
|                             else { | ||||
|                                 new_t = new_new_t; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 else { | ||||
|                     // the model has an interpretaion for f.
 | ||||
|                     if (num_args == 0) { | ||||
|                         // t is a constant
 | ||||
|                         new_t = get_const_interp(f); | ||||
|                     } | ||||
|                     else { | ||||
|                         // t is a function application
 | ||||
|                         SASSERT(new_t.get() == 0); | ||||
|                         // try to use function graph first
 | ||||
|                         func_interp * fi = get_func_interp(f); | ||||
|                         SASSERT(fi->get_arity() == num_args); | ||||
|                         expr_ref r1(m_manager); | ||||
|                         // fi may be partial...
 | ||||
|                         if (!::eval(*fi, m_simplifier, args.c_ptr(), r1)) { | ||||
|                             SASSERT(fi->is_partial()); // fi->eval only fails when fi is partial.
 | ||||
|                             if (model_completion) { | ||||
|                                 expr * r = get_some_value(f->get_range());  | ||||
|                                 fi->set_else(r); | ||||
|                                 SASSERT(!fi->is_partial()); | ||||
|                                 new_t = r; | ||||
|                             } | ||||
|                             else { | ||||
|                                 // f is an uninterpreted function, there is no need to use m_simplifier.mk_app
 | ||||
|                                 new_t = m_manager.mk_app(f, num_args, args.c_ptr()); | ||||
|                                 trail.push_back(new_t); | ||||
|                                 TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";); | ||||
|                                 is_ok = false; | ||||
|                             } | ||||
|                         } | ||||
|                         else { | ||||
|                             SASSERT(r1); | ||||
|                             trail.push_back(r1); | ||||
|                             TRACE("model_eval", tout << mk_pp(a, m_manager) << "\nevaluates to: " << r1 << "\n";); | ||||
|                             expr * r2 = 0; | ||||
|                             if (!eval_cache.find(r1.get(), r2)) { | ||||
|                                 todo.back().second = r1; | ||||
|                                 todo.push_back(std::make_pair(r1, null)); | ||||
|                                 continue; | ||||
|                             } | ||||
|                             else { | ||||
|                                 new_t = r2; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 TRACE("model_eval",  | ||||
|                       tout << "orig:\n" << mk_pp(t, m_manager) << "\n"; | ||||
|                       tout << "new:\n" << mk_pp(new_t, m_manager) << "\n";); | ||||
|                 todo.pop_back(); | ||||
|                 SASSERT(new_t.get() != 0); | ||||
|                 eval_cache.insert(t, new_t); | ||||
|                 break; | ||||
|             } | ||||
|             case AST_VAR:   | ||||
|                 SASSERT(a != 0); | ||||
|                 eval_cache.insert(a, a); | ||||
|                 todo.pop_back(); | ||||
|                 break; | ||||
|             case AST_QUANTIFIER:  | ||||
|                 TRACE("model_eval", tout << "found quantifier\n" << mk_pp(a, m_manager) << "\n";); | ||||
|                 is_ok = false; // evaluator does not handle quantifiers.
 | ||||
|                 SASSERT(a != 0); | ||||
|                 eval_cache.insert(a, a); | ||||
|                 todo.pop_back(); | ||||
|                 break; | ||||
|             default: | ||||
|                 UNREACHABLE(); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     catch (model_evaluator_exception & ex) { | ||||
|         (void)ex; | ||||
|         TRACE("model_evaluator", tout << ex.msg() << "\n";); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (!eval_cache.find(e, a)) { | ||||
|         TRACE("model_eval", tout << "FAILED e: " << mk_bounded_pp(e, m_manager) << "\n";); | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     result = a; | ||||
|     TRACE("model_eval",  | ||||
|           ast_ll_pp(tout << "original:  ", m_manager, e); | ||||
|           ast_ll_pp(tout << "evaluated: ", m_manager, a); | ||||
|           ast_ll_pp(tout << "reduced:   ", m_manager, result.get()); | ||||
|           tout << "sort: " << mk_pp(m_manager.get_sort(e), m_manager) << "\n"; | ||||
|           );  | ||||
|     SASSERT(is_well_sorted(m_manager, result.get())); | ||||
|     return is_ok; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -400,7 +167,7 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au | |||
|                 if (m_aux_decls.contains(f)) | ||||
|                     found_aux_fs.insert(f); | ||||
|                 expr_ref new_t(m_manager); | ||||
|                 m_simplifier.mk_app(f, num_args, args.c_ptr(), new_t); | ||||
|                 new_t = m_rewrite.mk_app(f, num_args, args.c_ptr()); | ||||
|                 if (t != new_t.get()) | ||||
|                     trail.push_back(new_t); | ||||
|                 todo.pop_back(); | ||||
|  |  | |||
|  | @ -32,23 +32,22 @@ Revision History: | |||
| #include"model_evaluator.h" | ||||
| #include"value_factory.h" | ||||
| #include"plugin_manager.h" | ||||
| #include"simplifier.h" | ||||
| #include"arith_decl_plugin.h" | ||||
| #include"func_decl_dependencies.h" | ||||
| #include"model.h" | ||||
| #include"params.h" | ||||
| #include"th_rewriter.h" | ||||
| 
 | ||||
| class proto_model : public model_core { | ||||
|     plugin_manager<value_factory> m_factories; | ||||
|     user_sort_factory *           m_user_sort_factory; | ||||
|     simplifier &                  m_simplifier; | ||||
|     family_id                     m_afid;        //!< array family id: hack for displaying models in V1.x style
 | ||||
|     func_decl_set                 m_aux_decls; | ||||
|     ptr_vector<expr>              m_tmp; | ||||
|     model_evaluator               m_eval; | ||||
|     th_rewriter                   m_rewrite; | ||||
| 
 | ||||
|     bool                          m_model_partial; | ||||
|     bool                          m_use_new_eval; | ||||
| 
 | ||||
|     expr * mk_some_interp_for(func_decl * d); | ||||
| 
 | ||||
|  | @ -62,7 +61,7 @@ class proto_model : public model_core { | |||
|     bool is_select_of_model_value(expr* e) const; | ||||
| 
 | ||||
| public: | ||||
|     proto_model(ast_manager & m, simplifier & s, params_ref const & p = params_ref()); | ||||
|     proto_model(ast_manager & m, params_ref const & p = params_ref()); | ||||
|     virtual ~proto_model() {} | ||||
| 
 | ||||
|     void register_factory(value_factory * f) { m_factories.register_plugin(f); } | ||||
|  |  | |||
|  | @ -122,6 +122,10 @@ namespace smt { | |||
|         */ | ||||
|         lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0); | ||||
| 
 | ||||
|         lbool check(expr_ref_vector const& asms) { return check(asms.size(), asms.c_ptr()); } | ||||
| 
 | ||||
|         lbool check(app_ref_vector const& asms) { return check(asms.size(), (expr* const*)asms.c_ptr()); } | ||||
| 
 | ||||
|         /**
 | ||||
|            \brief Return the model associated with the last check command. | ||||
|         */ | ||||
|  |  | |||
|  | @ -49,7 +49,7 @@ namespace smt { | |||
|     void model_generator::init_model() { | ||||
|         SASSERT(!m_model); | ||||
|         // PARAM-TODO smt_params ---> params_ref
 | ||||
|         m_model = alloc(proto_model, m_manager, m_context->get_simplifier()); // , m_context->get_fparams());
 | ||||
|         m_model = alloc(proto_model, m_manager); // , m_context->get_fparams());
 | ||||
|         ptr_vector<theory>::const_iterator it  = m_context->begin_theories(); | ||||
|         ptr_vector<theory>::const_iterator end = m_context->end_theories(); | ||||
|         for (; it != end; ++it) { | ||||
|  |  | |||
|  | @ -315,10 +315,7 @@ namespace smt { | |||
|             return m_var2enode_lim[m_var2enode_lim.size() - num_scopes]; | ||||
|         } | ||||
|          | ||||
|         virtual void display(std::ostream & out) const { | ||||
|             out << "Theory " << static_cast<int>(get_id()) << typeid(*this).name() << " does not have a display method\n"; | ||||
|             display_var2enode(out); | ||||
|         } | ||||
|         virtual void display(std::ostream & out) const = 0; | ||||
| 
 | ||||
|         virtual void display_var2enode(std::ostream & out) const; | ||||
|          | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ namespace smt { | |||
|         virtual bool build_models() const {  | ||||
|             return false; | ||||
|         } | ||||
|         virtual void display(std::ostream& out) const {} | ||||
| 
 | ||||
|     public: | ||||
|         theory_dummy(family_id fid, char const * name); | ||||
|  |  | |||
|  | @ -122,6 +122,7 @@ namespace smt { | |||
|         virtual void new_diseq_eh(theory_var, theory_var) {} | ||||
|         virtual theory* mk_fresh(context* new_ctx) { return alloc(theory_seq_empty, new_ctx->get_manager()); } | ||||
|         virtual char const * get_name() const { return "seq-empty"; } | ||||
|         virtual void display(std::ostream& out) const {} | ||||
|     public: | ||||
|         theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {} | ||||
|         virtual void init_model(model_generator & mg) { | ||||
|  |  | |||
|  | @ -94,6 +94,7 @@ namespace smt { | |||
|         virtual bool internalize_term(app * term) { return false; } | ||||
|         virtual void new_eq_eh(theory_var v1, theory_var v2) { } | ||||
|         virtual void new_diseq_eh(theory_var v1, theory_var v2) { } | ||||
|         virtual void display(std::ostream& out) const {} | ||||
| 
 | ||||
|         virtual void collect_statistics(::statistics & st) const { | ||||
|             st.update("wmaxsat num blocks", m_stats.m_num_blocks); | ||||
|  |  | |||
|  | @ -194,7 +194,7 @@ public: | |||
|         m_use_solver1_results = false; | ||||
| 
 | ||||
|         if (get_num_assumptions() != 0 ||             | ||||
|             num_assumptions > 0 || // assumptions were provided
 | ||||
|             num_assumptions > 0 ||  // assumptions were provided
 | ||||
|             m_ignore_solver1)  { | ||||
|             // must use incremental solver
 | ||||
|             switch_inc_mode(); | ||||
|  |  | |||
|  | @ -23,12 +23,11 @@ Notes: | |||
| #include"ast_smt2_pp.h" | ||||
| 
 | ||||
| solver_na2as::solver_na2as(ast_manager & m): | ||||
|     m_manager(m) { | ||||
|     m(m),  | ||||
|     m_assumptions(m) { | ||||
| } | ||||
| 
 | ||||
| solver_na2as::~solver_na2as() { | ||||
|     restore_assumptions(0); | ||||
| } | ||||
| solver_na2as::~solver_na2as() {} | ||||
| 
 | ||||
| void solver_na2as::assert_expr(expr * t, expr * a) { | ||||
|     if (a == 0) { | ||||
|  | @ -36,20 +35,19 @@ void solver_na2as::assert_expr(expr * t, expr * a) { | |||
|     } | ||||
|     else { | ||||
|         SASSERT(is_uninterp_const(a)); | ||||
|         SASSERT(m_manager.is_bool(a)); | ||||
|         TRACE("solver_na2as", tout << "asserting\n" << mk_ismt2_pp(t, m_manager) << "\n" << mk_ismt2_pp(a, m_manager) << "\n";); | ||||
|         m_manager.inc_ref(a); | ||||
|         SASSERT(m.is_bool(a)); | ||||
|         TRACE("solver_na2as", tout << "asserting\n" << mk_ismt2_pp(t, m) << "\n" << mk_ismt2_pp(a, m) << "\n";); | ||||
|         m_assumptions.push_back(a); | ||||
|         expr_ref new_t(m_manager); | ||||
|         new_t = m_manager.mk_implies(a, t); | ||||
|         expr_ref new_t(m); | ||||
|         new_t = m.mk_implies(a, t); | ||||
|         assert_expr(new_t); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct append_assumptions { | ||||
|     ptr_vector<expr> & m_assumptions; | ||||
|     expr_ref_vector & m_assumptions; | ||||
|     unsigned           m_old_sz; | ||||
|     append_assumptions(ptr_vector<expr> & _m_assumptions,  | ||||
|     append_assumptions(expr_ref_vector & _m_assumptions,  | ||||
|                        unsigned num_assumptions,  | ||||
|                        expr * const * assumptions): | ||||
|         m_assumptions(_m_assumptions) { | ||||
|  | @ -82,10 +80,6 @@ void solver_na2as::pop(unsigned n) { | |||
| } | ||||
| 
 | ||||
| void solver_na2as::restore_assumptions(unsigned old_sz) { | ||||
|   //    SASSERT(old_sz == 0);
 | ||||
|     for (unsigned i = old_sz; i < m_assumptions.size(); i++) { | ||||
|         m_manager.dec_ref(m_assumptions[i]); | ||||
|     } | ||||
|     m_assumptions.shrink(old_sz); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,8 +25,8 @@ Notes: | |||
| #include"solver.h" | ||||
| 
 | ||||
| class solver_na2as : public solver { | ||||
|     ast_manager &      m_manager; | ||||
|     ptr_vector<expr>   m_assumptions; | ||||
|     ast_manager &      m; | ||||
|     expr_ref_vector    m_assumptions; | ||||
|     unsigned_vector    m_scopes; | ||||
|     void restore_assumptions(unsigned old_sz); | ||||
| public: | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ class nla2bv_tactic : public tactic { | |||
|         expr_ref_vector             m_trail; | ||||
|         unsigned                    m_num_bits; | ||||
|         unsigned                    m_default_bv_size; | ||||
|         ref<filter_model_converter> m_fmc; | ||||
|         filter_model_converter_ref  m_fmc; | ||||
|          | ||||
|     public: | ||||
|         imp(ast_manager & m, params_ref const& p): | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ struct bv_size_reduction_tactic::imp { | |||
|     obj_map<app, numeral>     m_unsigned_lowers; | ||||
|     obj_map<app, numeral>     m_unsigned_uppers; | ||||
|     ref<bv_size_reduction_mc> m_mc; | ||||
|     ref<filter_model_converter> m_fmc; | ||||
|     filter_model_converter_ref m_fmc; | ||||
|     scoped_ptr<expr_replacer> m_replacer; | ||||
|     bool                      m_produce_models; | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ Revision History: | |||
| 
 | ||||
| class propagate_values_tactic : public tactic { | ||||
|     struct     imp { | ||||
|         ast_manager &                 m_manager; | ||||
|         ast_manager &                 m; | ||||
|         th_rewriter                   m_r; | ||||
|         scoped_ptr<expr_substitution> m_subst; | ||||
|         goal *                        m_goal; | ||||
|  | @ -36,13 +36,15 @@ class propagate_values_tactic : public tactic { | |||
|         bool                          m_modified; | ||||
|          | ||||
|         imp(ast_manager & m, params_ref const & p): | ||||
|             m_manager(m), | ||||
|             m(m), | ||||
|             m_r(m, p), | ||||
|             m_goal(0), | ||||
|             m_occs(m, true /* track atoms */) { | ||||
|             updt_params_core(p); | ||||
|         } | ||||
| 
 | ||||
|         ~imp() { } | ||||
| 
 | ||||
|         void updt_params_core(params_ref const & p) { | ||||
|             m_max_rounds = p.get_uint("max_rounds", 4); | ||||
|         } | ||||
|  | @ -51,32 +53,28 @@ class propagate_values_tactic : public tactic { | |||
|             m_r.updt_params(p); | ||||
|             updt_params_core(p); | ||||
|         } | ||||
| 
 | ||||
|         ast_manager & m() const { return m_manager; } | ||||
|          | ||||
|          | ||||
|         bool is_shared(expr * t) { | ||||
|             return m_occs.is_shared(t); | ||||
|         } | ||||
|          | ||||
|         bool is_shared_neg(expr * t, expr * & atom) { | ||||
|             if (!m().is_not(t)) | ||||
|         bool is_shared_neg(expr * t, expr * & atom) {             | ||||
|             if (!m.is_not(t, atom)) | ||||
|                 return false; | ||||
|             atom = to_app(t)->get_arg(0); | ||||
|             return is_shared(atom); | ||||
|         } | ||||
| 
 | ||||
|         bool is_shared_eq(expr * t, expr * & lhs, expr * & value) { | ||||
|             if (!m().is_eq(t)) | ||||
|             expr* arg1, *arg2; | ||||
|             if (!m.is_eq(t, arg1, arg2)) | ||||
|                 return false; | ||||
|             expr * arg1 = to_app(t)->get_arg(0); | ||||
|             expr * arg2 = to_app(t)->get_arg(1); | ||||
|             if (m().is_value(arg1) && is_shared(arg2)) { | ||||
|             if (m.is_value(arg1) && is_shared(arg2)) { | ||||
|                 lhs   = arg2; | ||||
|                 value = arg1; | ||||
|                 return true; | ||||
|             } | ||||
|             if (m().is_value(arg2) && is_shared(arg1)) { | ||||
|             if (m.is_value(arg2) && is_shared(arg1)) { | ||||
|                 lhs   = arg1; | ||||
|                 value = arg2; | ||||
|                 return true; | ||||
|  | @ -87,15 +85,15 @@ class propagate_values_tactic : public tactic { | |||
|         void push_result(expr * new_curr, proof * new_pr) { | ||||
|             if (m_goal->proofs_enabled()) { | ||||
|                 proof * pr = m_goal->pr(m_idx); | ||||
|                 new_pr     = m().mk_modus_ponens(pr, new_pr); | ||||
|                 new_pr     = m.mk_modus_ponens(pr, new_pr); | ||||
|             } | ||||
|              | ||||
|             expr_dependency_ref new_d(m()); | ||||
|             expr_dependency_ref new_d(m); | ||||
|             if (m_goal->unsat_core_enabled()) { | ||||
|                 new_d = m_goal->dep(m_idx); | ||||
|                 expr_dependency * used_d = m_r.get_used_dependencies(); | ||||
|                 if (used_d != 0) { | ||||
|                     new_d = m().mk_join(new_d, used_d); | ||||
|                     new_d = m.mk_join(new_d, used_d); | ||||
|                     m_r.reset_used_dependencies(); | ||||
|                 } | ||||
|             } | ||||
|  | @ -103,34 +101,34 @@ class propagate_values_tactic : public tactic { | |||
|             m_goal->update(m_idx, new_curr, new_pr, new_d); | ||||
|          | ||||
|             if (is_shared(new_curr)) { | ||||
|                 m_subst->insert(new_curr, m().mk_true(), m().mk_iff_true(new_pr), new_d); | ||||
|                 m_subst->insert(new_curr, m.mk_true(), m.mk_iff_true(new_pr), new_d); | ||||
|             } | ||||
|             expr * atom; | ||||
|             if (is_shared_neg(new_curr, atom)) { | ||||
|                 m_subst->insert(atom, m().mk_false(), m().mk_iff_false(new_pr), new_d); | ||||
|                 m_subst->insert(atom, m.mk_false(), m.mk_iff_false(new_pr), new_d); | ||||
|             } | ||||
|             expr * lhs, * value; | ||||
|             if (is_shared_eq(new_curr, lhs, value)) { | ||||
|                 TRACE("shallow_context_simplifier_bug", tout << "found eq:\n" << mk_ismt2_pp(new_curr, m()) << "\n";); | ||||
|                 TRACE("shallow_context_simplifier_bug", tout << "found eq:\n" << mk_ismt2_pp(new_curr, m) << "\n";); | ||||
|                 m_subst->insert(lhs, value, new_pr, new_d); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         void process_current() { | ||||
|             expr * curr = m_goal->form(m_idx); | ||||
|             expr_ref   new_curr(m()); | ||||
|             proof_ref  new_pr(m()); | ||||
|             expr_ref   new_curr(m); | ||||
|             proof_ref  new_pr(m); | ||||
|              | ||||
|             if (!m_subst->empty()) { | ||||
|                 m_r(curr, new_curr, new_pr); | ||||
|             } | ||||
|             else { | ||||
|                 new_curr = curr; | ||||
|                 if (m().proofs_enabled()) | ||||
|                     new_pr   = m().mk_reflexivity(curr); | ||||
|                 if (m.proofs_enabled()) | ||||
|                     new_pr   = m.mk_reflexivity(curr); | ||||
|             } | ||||
| 
 | ||||
|             TRACE("shallow_context_simplifier_bug", tout << mk_ismt2_pp(curr, m()) << "\n---->\n" << mk_ismt2_pp(new_curr, m()) << "\n";); | ||||
|             TRACE("shallow_context_simplifier_bug", tout << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n";); | ||||
|             push_result(new_curr, new_pr); | ||||
|              | ||||
|             if (new_curr != curr) | ||||
|  | @ -148,25 +146,26 @@ class propagate_values_tactic : public tactic { | |||
|             m_goal = g.get(); | ||||
| 
 | ||||
|             bool forward   = true; | ||||
|             expr_ref   new_curr(m()); | ||||
|             proof_ref  new_pr(m()); | ||||
|             expr_ref   new_curr(m); | ||||
|             proof_ref  new_pr(m); | ||||
|             unsigned size  = m_goal->size(); | ||||
|             m_idx          = 0; | ||||
|             m_modified     = false; | ||||
|             unsigned round = 0; | ||||
| 
 | ||||
| 
 | ||||
|             if (m_goal->inconsistent()) | ||||
|                 goto end; | ||||
| 
 | ||||
|             if (m_max_rounds == 0) | ||||
|                 goto end; | ||||
| 
 | ||||
|             m_subst = alloc(expr_substitution, m(), g->unsat_core_enabled(), g->proofs_enabled()); | ||||
|             m_subst = alloc(expr_substitution, m, g->unsat_core_enabled(), g->proofs_enabled()); | ||||
|             m_r.set_substitution(m_subst.get()); | ||||
|             m_occs(*m_goal); | ||||
| 
 | ||||
|             while (true) { | ||||
|                 TRACE("propagate_values", tout << "while(true) loop\n"; m_goal->display(tout);); | ||||
|                 TRACE("propagate_values", tout << "while(true) loop\n"; m_goal->display_with_dependencies(tout);); | ||||
|                 if (forward) { | ||||
|                     for (; m_idx < size; m_idx++) { | ||||
|                         process_current(); | ||||
|  | @ -255,15 +254,14 @@ public: | |||
|     } | ||||
|      | ||||
|     virtual void cleanup() { | ||||
|         ast_manager & m = m_imp->m(); | ||||
|         imp * d = alloc(imp, m, m_params); | ||||
|         std::swap(d, m_imp);         | ||||
|         dealloc(d); | ||||
|         ast_manager & m = m_imp->m; | ||||
|         dealloc(m_imp); | ||||
|         m_imp = alloc(imp, m, m_params); | ||||
|     } | ||||
|      | ||||
| }; | ||||
| 
 | ||||
| tactic * mk_propagate_values_tactic(ast_manager & m, params_ref const & p) { | ||||
|     return clean(alloc(propagate_values_tactic, m, p)); | ||||
|     return alloc(propagate_values_tactic, m, p); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,7 +22,9 @@ Notes: | |||
| #include"smt_tactic.h" | ||||
| #include"nnf_tactic.h" | ||||
| #include"qe_tactic.h" | ||||
| #include"nlqsat.h" | ||||
| #include"qfnra_nlsat_tactic.h" | ||||
| #include"qe_lite.h" | ||||
| #include"probe_arith.h" | ||||
| 
 | ||||
| tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) { | ||||
|  | @ -36,12 +38,19 @@ tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) { | |||
|     return and_then(mk_simplify_tactic(m, p), | ||||
|                     mk_nnf_tactic(m, p), | ||||
|                     mk_propagate_values_tactic(m, p), | ||||
|                     //mk_qe_lite_tactic(m), 
 | ||||
|                     mk_qe_tactic(m, p), | ||||
|                     cond(mk_is_qfnra_probe(), | ||||
|                          or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000), | ||||
|                                  try_for(mk_qfnra_nlsat_tactic(m, p1), 10000), | ||||
|                                  mk_qfnra_nlsat_tactic(m, p2)), | ||||
|                          mk_smt_tactic(p))); | ||||
| #if 0 | ||||
|                          or_else(mk_nlqsat_tactic(m, p), | ||||
|                                  mk_smt_tactic(p)) | ||||
| #else | ||||
|                          mk_smt_tactic(p) | ||||
| #endif | ||||
|                          )); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,6 +23,9 @@ Revision History: | |||
| #include"elim_uncnstr_tactic.h" | ||||
| #include"qe_tactic.h" | ||||
| #include"qe_sat_tactic.h" | ||||
| #include"qe_lite.h" | ||||
| #include"qsat.h" | ||||
| #include"nlqsat.h" | ||||
| #include"ctx_simplify_tactic.h" | ||||
| #include"smt_tactic.h" | ||||
| 
 | ||||
|  | @ -37,10 +40,12 @@ static tactic * mk_quant_preprocessor(ast_manager & m, bool disable_gaussian = f | |||
|     ctx_simp_p.set_uint("max_steps", 5000000); | ||||
| 
 | ||||
|     tactic * solve_eqs; | ||||
|     if (disable_gaussian) | ||||
|     if (disable_gaussian) { | ||||
|         solve_eqs = mk_skip_tactic(); | ||||
|     else | ||||
|     } | ||||
|     else { | ||||
|         solve_eqs = when(mk_not(mk_has_pattern_probe()), mk_solve_eqs_tactic(m)); | ||||
|     } | ||||
|   | ||||
|     // remark: investigate if gaussian elimination is useful when patterns are not provided.
 | ||||
|     return and_then(mk_simplify_tactic(m),  | ||||
|  | @ -49,6 +54,7 @@ static tactic * mk_quant_preprocessor(ast_manager & m, bool disable_gaussian = f | |||
|                     using_params(mk_simplify_tactic(m), pull_ite_p), | ||||
|                     solve_eqs, | ||||
|                     mk_elim_uncnstr_tactic(m), | ||||
|                     mk_qe_lite_tactic(m), | ||||
|                     mk_simplify_tactic(m));     | ||||
| } | ||||
| 
 | ||||
|  | @ -98,13 +104,18 @@ tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p) { | |||
| } | ||||
| 
 | ||||
| tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { | ||||
| #if 0 | ||||
|     tactic * st = and_then(mk_quant_preprocessor(m), | ||||
|                            or_else(try_for(mk_smt_tactic(), 100),  | ||||
|                                    try_for(qe::mk_sat_tactic(m), 1000),  | ||||
|                                    try_for(mk_smt_tactic(), 1000), | ||||
|                                    and_then(mk_qe_tactic(m), mk_smt_tactic()) | ||||
|                                    )); | ||||
| 
 | ||||
| #else | ||||
|     tactic * st = and_then(mk_quant_preprocessor(m), | ||||
|                            or_else(mk_qsat_tactic(m, p), | ||||
|                                    and_then(mk_qe_tactic(m), mk_smt_tactic()))); | ||||
| #endif | ||||
|     st->updt_params(p); | ||||
|     return st; | ||||
| } | ||||
|  | @ -116,3 +127,4 @@ tactic * mk_lia_tactic(ast_manager & m, params_ref const & p) { | |||
| tactic * mk_lira_tactic(ast_manager & m, params_ref const & p) { | ||||
|     return mk_lra_tactic(m, p); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -131,19 +131,19 @@ public: | |||
|         SASSERT(r1_size > 0);                                                                                | ||||
|         if (r1_size == 1) {                                                                                  | ||||
|             if (r1[0]->is_decided()) { | ||||
|                 result.push_back(r1[0]);                                                                     | ||||
|                 if (models_enabled) mc = mc1;                                                                                  | ||||
|                 result.push_back(r1[0]);     | ||||
|                 if (models_enabled) mc = mc1;  | ||||
|                 SASSERT(!pc); SASSERT(!core); | ||||
|                 return;                                                                                      | ||||
|             }                                                                                                | ||||
|             goal_ref r1_0 = r1[0];                                                                           | ||||
|             m_t2->operator()(r1_0, result, mc, pc, core);                                               | ||||
|             if (models_enabled) mc = concat(mc1.get(), mc.get());                                                                | ||||
|             if (proofs_enabled) pc = concat(pc1.get(), pc.get());                                                                | ||||
|             if (cores_enabled) core = m.mk_join(core1.get(), core);                                                             | ||||
|         }                                                                                      | ||||
|         else {                                                                                               | ||||
|             if (cores_enabled) core = core1;                                                                                    | ||||
|             goal_ref r1_0 = r1[0];       | ||||
|             m_t2->operator()(r1_0, result, mc, pc, core); | ||||
|             if (models_enabled) mc = concat(mc1.get(), mc.get()); | ||||
|             if (proofs_enabled) pc = concat(pc1.get(), pc.get());  | ||||
|             if (cores_enabled) core = m.mk_join(core1.get(), core);  | ||||
|         } | ||||
|         else { | ||||
|             if (cores_enabled) core = core1; | ||||
|             proof_converter_ref_buffer pc_buffer;                                                            | ||||
|             model_converter_ref_buffer mc_buffer;                                                            | ||||
|             sbuffer<unsigned>          sz_buffer;                                                            | ||||
|  | @ -179,16 +179,16 @@ public: | |||
|                         SASSERT(!core2); | ||||
|                         if (models_enabled) mc_buffer.push_back(0); | ||||
|                         if (proofs_enabled) pc_buffer.push_back(proof2proof_converter(m, r2[0]->pr(0))); | ||||
|                         if (models_enabled || proofs_enabled) sz_buffer.push_back(0);                                                              | ||||
|                         if (models_enabled || proofs_enabled) sz_buffer.push_back(0); | ||||
|                         if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); | ||||
|                     }                                                                          | ||||
|                 }                                                                                        | ||||
|                 else {                                                                                       | ||||
|                     result.append(r2.size(), r2.c_ptr());                                                    | ||||
|                     if (models_enabled) mc_buffer.push_back(mc2.get());                                                          | ||||
|                     if (proofs_enabled) pc_buffer.push_back(pc2.get());                                                          | ||||
|                     if (models_enabled || proofs_enabled) sz_buffer.push_back(r2.size());                                                          | ||||
|                     if (cores_enabled) core = m.mk_join(core.get(), core2.get());                                               | ||||
|                     result.append(r2.size(), r2.c_ptr()); | ||||
|                     if (models_enabled) mc_buffer.push_back(mc2.get()); | ||||
|                     if (proofs_enabled) pc_buffer.push_back(pc2.get()); | ||||
|                     if (models_enabled || proofs_enabled) sz_buffer.push_back(r2.size());  | ||||
|                     if (cores_enabled) core = m.mk_join(core.get(), core2.get()); | ||||
|                 }                                                                                            | ||||
|             } | ||||
|              | ||||
|  | @ -651,12 +651,12 @@ public: | |||
|             }                                                                                                | ||||
|             goal_ref r1_0 = r1[0];                                                                           | ||||
|             m_t2->operator()(r1_0, result, mc, pc, core);                                               | ||||
|             if (models_enabled) mc = concat(mc1.get(), mc.get());                                                                | ||||
|             if (proofs_enabled) pc = concat(pc1.get(), pc.get());                                                                | ||||
|             if (cores_enabled) core = m.mk_join(core1.get(), core);                                                             | ||||
|             if (models_enabled) mc = concat(mc1.get(), mc.get()); | ||||
|             if (proofs_enabled) pc = concat(pc1.get(), pc.get()); | ||||
|             if (cores_enabled) core = m.mk_join(core1.get(), core);  | ||||
|         }                                                                                      | ||||
|         else {                                                                                               | ||||
|             if (cores_enabled) core = core1;                                                                                    | ||||
|             if (cores_enabled) core = core1;   | ||||
| 
 | ||||
|             scoped_ptr_vector<ast_manager> managers; | ||||
|             tactic_ref_vector              ts2; | ||||
|  | @ -670,8 +670,8 @@ public: | |||
|                 ts2.push_back(m_t2->translate(*new_m)); | ||||
|             } | ||||
| 
 | ||||
|             proof_converter_ref_buffer             pc_buffer;                                                            | ||||
|             model_converter_ref_buffer             mc_buffer;                                                            | ||||
|             proof_converter_ref_buffer             pc_buffer;  | ||||
|             model_converter_ref_buffer             mc_buffer;  | ||||
|             scoped_ptr_vector<expr_dependency_ref> core_buffer; | ||||
|             scoped_ptr_vector<goal_ref_buffer>     goals_vect; | ||||
| 
 | ||||
|  | @ -687,7 +687,7 @@ public: | |||
|             std::string  ex_msg; | ||||
| 
 | ||||
|             #pragma omp parallel for | ||||
|             for (int i = 0; i < static_cast<int>(r1_size); i++) {                                                         | ||||
|             for (int i = 0; i < static_cast<int>(r1_size); i++) {  | ||||
|                 ast_manager & new_m = *(managers[i]); | ||||
|                 goal_ref new_g = g_copies[i]; | ||||
| 
 | ||||
|  | @ -772,7 +772,7 @@ public: | |||
|                                     md = alloc(model, m); | ||||
|                                     apply(mc2, md, 0); | ||||
|                                     apply(mc1, md, i); | ||||
|                                     mc   = model2model_converter(md.get());                                              | ||||
|                                     mc   = model2model_converter(md.get()); | ||||
|                                 } | ||||
|                                 SASSERT(!pc); SASSERT(!core); | ||||
|                             }        | ||||
|  | @ -969,9 +969,9 @@ class repeat_tactical : public unary_tactical { | |||
|             m_t->operator()(in, r1, mc1, pc1, core1);                                                             | ||||
|             if (is_equal(orig_in, *(in.get()))) { | ||||
|                 result.push_back(r1[0]);                                                                     | ||||
|                 if (models_enabled) mc = mc1;                                                                                  | ||||
|                 if (proofs_enabled) pc = pc1;                                                                                  | ||||
|                 if (cores_enabled)  core = core1;                                                                                | ||||
|                 if (models_enabled) mc = mc1; | ||||
|                 if (proofs_enabled) pc = pc1; | ||||
|                 if (cores_enabled)  core = core1;  | ||||
|                 return;                                                                                      | ||||
|             } | ||||
|         } | ||||
|  | @ -980,18 +980,18 @@ class repeat_tactical : public unary_tactical { | |||
|         if (r1_size == 1) {                                                                                  | ||||
|             if (r1[0]->is_decided()) { | ||||
|                 result.push_back(r1[0]);                                                                     | ||||
|                 if (models_enabled) mc = mc1;                                                                                  | ||||
|                 if (models_enabled) mc = mc1; | ||||
|                 SASSERT(!pc); SASSERT(!core); | ||||
|                 return;                                                                                      | ||||
|             }                                                                                                | ||||
|             goal_ref r1_0 = r1[0];                                                                           | ||||
|             operator()(depth+1, r1_0, result, mc, pc, core);                                               | ||||
|             if (models_enabled) mc = concat(mc.get(), mc1.get());                                                                | ||||
|             if (proofs_enabled) pc = concat(pc.get(), pc1.get());                                                                | ||||
|             if (cores_enabled)  core = m.mk_join(core1.get(), core);                                                             | ||||
|             operator()(depth+1, r1_0, result, mc, pc, core);  | ||||
|             if (models_enabled) mc = concat(mc.get(), mc1.get()); | ||||
|             if (proofs_enabled) pc = concat(pc.get(), pc1.get());  | ||||
|             if (cores_enabled)  core = m.mk_join(core1.get(), core);  | ||||
|         }                                                                                                    | ||||
|         else {                                                                                               | ||||
|             if (cores_enabled) core = core1;                                                                                    | ||||
|         else { | ||||
|             if (cores_enabled) core = core1; | ||||
|             proof_converter_ref_buffer pc_buffer;                                                            | ||||
|             model_converter_ref_buffer mc_buffer;                                                            | ||||
|             sbuffer<unsigned>          sz_buffer;                                                            | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ Notes: | |||
| #include"nlsat_evaluator.h" | ||||
| #include"nlsat_solver.h" | ||||
| #include"util.h" | ||||
| #include"nlsat_explain.h" | ||||
| #include"polynomial_cache.h" | ||||
| #include"rlimit.h" | ||||
| 
 | ||||
| nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1, | ||||
|  | @ -29,7 +31,6 @@ nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1, | |||
|                                      bool check_num_intervals = true) { | ||||
|     nlsat::interval_set_manager & ism = s1.m(); | ||||
|     nlsat::interval_set_ref r(ism); | ||||
|     std::cout << "------------------\n"; | ||||
|     std::cout << "s1:            " << s1 << "\n"; | ||||
|     std::cout << "s2:            " << s2 << "\n"; | ||||
|     r = ism.mk_union(s1, s2); | ||||
|  | @ -277,10 +278,12 @@ static void tst5() { | |||
|     nlsat::assignment           as(am); | ||||
|     small_object_allocator      allocator; | ||||
|     nlsat::interval_set_manager ism(am, allocator); | ||||
|     nlsat::evaluator            ev(as, pm, allocator); | ||||
|     nlsat::evaluator            ev(s, as, pm, allocator); | ||||
|     nlsat::var                  x0, x1; | ||||
|     x0 = pm.mk_var(); | ||||
|     x1 = pm.mk_var(); | ||||
|     nlsat::interval_set_ref i(ism); | ||||
| 
 | ||||
|     polynomial_ref p(pm); | ||||
|     polynomial_ref _x0(pm), _x1(pm); | ||||
|     _x0 = pm.mk_polynomial(x0); | ||||
|  | @ -291,7 +294,6 @@ static void tst5() { | |||
|     nlsat::bool_var b = s.mk_ineq_atom(nlsat::atom::GT, 1, _p, is_even); | ||||
|     nlsat::atom * a = s.bool_var2atom(b); | ||||
|     SASSERT(a != 0); | ||||
|     nlsat::interval_set_ref  i(ism); | ||||
|     scoped_anum zero(am); | ||||
|     am.set(zero, 0); | ||||
|     as.set(0, zero); | ||||
|  | @ -302,8 +304,414 @@ static void tst5() { | |||
|     std::cout << "2) " << i << "\n"; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static void project(nlsat::solver& s, nlsat::explain& ex, nlsat::var x, unsigned num, nlsat::literal const* lits) { | ||||
|     std::cout << "Project "; | ||||
|     s.display(std::cout, num, lits); | ||||
|     nlsat::scoped_literal_vector result(s); | ||||
|     ex.project(x, num, lits, result); | ||||
|     s.display(std::cout << "\n==>\n", result.size(), result.c_ptr()); | ||||
|     std::cout << "\n"; | ||||
| } | ||||
| 
 | ||||
| static nlsat::literal mk_gt(nlsat::solver& s, nlsat::poly* p) { | ||||
|     nlsat::poly * _p[1] = { p }; | ||||
|     bool is_even[1] = { false }; | ||||
|     return s.mk_ineq_literal(nlsat::atom::GT, 1, _p, is_even); | ||||
| } | ||||
| 
 | ||||
| static nlsat::literal mk_eq(nlsat::solver& s, nlsat::poly* p) { | ||||
|     nlsat::poly * _p[1] = { p }; | ||||
|     bool is_even[1] = { false }; | ||||
|     return s.mk_ineq_literal(nlsat::atom::EQ, 1, _p, is_even); | ||||
| } | ||||
| 
 | ||||
| static void tst6() { | ||||
|     params_ref      ps; | ||||
|     reslimit        rlim; | ||||
|     nlsat::solver s(rlim, ps); | ||||
|     anum_manager & am     = s.am(); | ||||
|     nlsat::pmanager & pm  = s.pm(); | ||||
|     nlsat::assignment as(am); | ||||
|     nlsat::explain& ex    = s.get_explain(); | ||||
|     nlsat::var x0, x1, x2, a, b, c, d; | ||||
|     a  = s.mk_var(false); | ||||
|     b  = s.mk_var(false); | ||||
|     c  = s.mk_var(false); | ||||
|     d  = s.mk_var(false); | ||||
|     x0 = s.mk_var(false); | ||||
|     x1 = s.mk_var(false); | ||||
|     x2 = s.mk_var(false); | ||||
| 
 | ||||
|     polynomial_ref p1(pm), p2(pm), p3(pm), p4(pm), p5(pm); | ||||
|     polynomial_ref _x0(pm), _x1(pm), _x2(pm); | ||||
|     polynomial_ref _a(pm), _b(pm), _c(pm), _d(pm); | ||||
|     _x0 = pm.mk_polynomial(x0); | ||||
|     _x1 = pm.mk_polynomial(x1); | ||||
|     _x2 = pm.mk_polynomial(x2); | ||||
|     _a  = pm.mk_polynomial(a); | ||||
|     _b  = pm.mk_polynomial(b); | ||||
|     _c  = pm.mk_polynomial(c); | ||||
|     _d  = pm.mk_polynomial(d); | ||||
| 
 | ||||
|     p1 = (_a*(_x0^2)) + _x2 + 2; | ||||
|     p2 = (_b*_x1) - (2*_x2) - _x0 + 8; | ||||
|     nlsat::scoped_literal_vector lits(s); | ||||
|     lits.push_back(mk_gt(s, p1)); | ||||
|     lits.push_back(mk_gt(s, p2)); | ||||
|     lits.push_back(mk_gt(s, (_c*_x0) + _x2 + 1)); | ||||
|     lits.push_back(mk_gt(s, (_d*_x0) - _x1 + 5*_x2)); | ||||
| 
 | ||||
|     scoped_anum zero(am), one(am), two(am); | ||||
|     am.set(zero, 0); | ||||
|     am.set(one,  1); | ||||
|     am.set(two,  2); | ||||
|     as.set(0, one); | ||||
|     as.set(1, one); | ||||
|     as.set(2, two); | ||||
|     as.set(3, two); | ||||
|     as.set(4, two); | ||||
|     as.set(5, one); | ||||
|     as.set(6, one);  | ||||
|     s.set_rvalues(as); | ||||
| 
 | ||||
| 
 | ||||
|     project(s, ex, x0, 2, lits.c_ptr()); | ||||
|     project(s, ex, x1, 3, lits.c_ptr()); | ||||
|     project(s, ex, x2, 3, lits.c_ptr()); | ||||
|     project(s, ex, x2, 2, lits.c_ptr()); | ||||
|     project(s, ex, x2, 4, lits.c_ptr()); | ||||
|     project(s, ex, x2, 3, lits.c_ptr()+1); | ||||
|      | ||||
|      | ||||
| } | ||||
| 
 | ||||
| static void tst7() { | ||||
|     params_ref      ps; | ||||
|     reslimit        rlim; | ||||
|     nlsat::solver s(rlim, ps); | ||||
|     anum_manager & am     = s.am(); | ||||
|     nlsat::pmanager & pm  = s.pm(); | ||||
|     nlsat::var x0, x1, x2, a, b, c, d; | ||||
|     a  = s.mk_var(false); | ||||
|     b  = s.mk_var(false); | ||||
|     c  = s.mk_var(false); | ||||
|     d  = s.mk_var(false); | ||||
|     x0 = s.mk_var(false); | ||||
|     x1 = s.mk_var(false); | ||||
|     x2 = s.mk_var(false); | ||||
|     polynomial_ref p1(pm), p2(pm), p3(pm), p4(pm), p5(pm); | ||||
|     polynomial_ref _x0(pm), _x1(pm), _x2(pm); | ||||
|     polynomial_ref _a(pm), _b(pm), _c(pm), _d(pm); | ||||
|     _x0 = pm.mk_polynomial(x0); | ||||
|     _x1 = pm.mk_polynomial(x1); | ||||
|     _x2 = pm.mk_polynomial(x2); | ||||
|     _a  = pm.mk_polynomial(a); | ||||
|     _b  = pm.mk_polynomial(b); | ||||
|     _c  = pm.mk_polynomial(c); | ||||
|     _d  = pm.mk_polynomial(d); | ||||
| 
 | ||||
|     p1 = _x0 + _x1; | ||||
|     p2 = _x2 - _x0; | ||||
|     p3 = (-1*_x0) - _x1; | ||||
|      | ||||
|     nlsat::scoped_literal_vector lits(s); | ||||
|     lits.push_back(mk_gt(s, p1)); | ||||
|     lits.push_back(mk_gt(s, p2)); | ||||
|     lits.push_back(mk_gt(s, p3)); | ||||
| 
 | ||||
|     nlsat::literal_vector litsv(lits.size(), lits.c_ptr()); | ||||
|     lbool res = s.check(litsv); | ||||
|     SASSERT(res == l_false); | ||||
|     for (unsigned i = 0; i < litsv.size(); ++i) { | ||||
|         s.display(std::cout, litsv[i]); | ||||
|         std::cout << " "; | ||||
|     } | ||||
|     std::cout << "\n"; | ||||
| 
 | ||||
|     litsv.reset(); | ||||
|     litsv.append(2, lits.c_ptr()); | ||||
|     res = s.check(litsv); | ||||
|     SASSERT(res == l_true); | ||||
|     s.display(std::cout); | ||||
|     s.am().display(std::cout, s.value(x0)); std::cout << "\n"; | ||||
|     s.am().display(std::cout, s.value(x1)); std::cout << "\n"; | ||||
|     s.am().display(std::cout, s.value(x2)); std::cout << "\n"; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void tst8() { | ||||
|     params_ref      ps; | ||||
|     reslimit        rlim; | ||||
|     nlsat::solver s(rlim, ps); | ||||
|     anum_manager & am     = s.am(); | ||||
|     nlsat::pmanager & pm  = s.pm(); | ||||
|     nlsat::assignment as(am); | ||||
|     nlsat::explain& ex    = s.get_explain(); | ||||
|     nlsat::var x0, x1, x2, a, b, c, d; | ||||
|     a  = s.mk_var(false); | ||||
|     b  = s.mk_var(false); | ||||
|     c  = s.mk_var(false); | ||||
|     d  = s.mk_var(false); | ||||
|     x0 = s.mk_var(false); | ||||
|     x1 = s.mk_var(false); | ||||
|     x2 = s.mk_var(false); | ||||
| 
 | ||||
|     polynomial_ref p1(pm), p2(pm), p3(pm), p4(pm), p5(pm); | ||||
|     polynomial_ref _x0(pm), _x1(pm), _x2(pm); | ||||
|     polynomial_ref _a(pm), _b(pm), _c(pm), _d(pm); | ||||
|     _x0 = pm.mk_polynomial(x0); | ||||
|     _x1 = pm.mk_polynomial(x1); | ||||
|     _x2 = pm.mk_polynomial(x2); | ||||
|     _a  = pm.mk_polynomial(a); | ||||
|     _b  = pm.mk_polynomial(b); | ||||
|     _c  = pm.mk_polynomial(c); | ||||
|     _d  = pm.mk_polynomial(d); | ||||
|      | ||||
|     scoped_anum zero(am), one(am), two(am), six(am); | ||||
|     am.set(zero, 0); | ||||
|     am.set(one,  1); | ||||
|     am.set(two,  2); | ||||
|     am.set(six,  6); | ||||
|     as.set(0, two); // a
 | ||||
|     as.set(1, one); // b
 | ||||
|     as.set(2, six); // c
 | ||||
|     as.set(3, zero); // d
 | ||||
|     as.set(4, zero); // x0
 | ||||
|     as.set(5, zero); // x1
 | ||||
|     as.set(6, two); // x2
 | ||||
|     s.set_rvalues(as); | ||||
| 
 | ||||
|     nlsat::scoped_literal_vector lits(s); | ||||
|     lits.push_back(mk_eq(s, (_a*_x2*_x2) - (_b*_x2) - _c)); | ||||
|     project(s, ex, x2, 1, lits.c_ptr()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static void tst9() { | ||||
|     params_ref      ps; | ||||
|     reslimit        rlim; | ||||
|     nlsat::solver s(rlim, ps); | ||||
|     anum_manager & am     = s.am(); | ||||
|     nlsat::pmanager & pm  = s.pm(); | ||||
|     nlsat::assignment as(am); | ||||
|     nlsat::explain& ex    = s.get_explain(); | ||||
|     int num_lo = 4; | ||||
|     int num_hi = 5; | ||||
|     svector<nlsat::var> los, his; | ||||
|     for (int i = 0; i < num_lo; ++i) { | ||||
|         los.push_back(s.mk_var(false)); | ||||
|         scoped_anum num(am); | ||||
|         am.set(num, - i - 1); | ||||
|         as.set(i, num); | ||||
|     } | ||||
|     for (int i = 0; i < num_hi; ++i) { | ||||
|         his.push_back(s.mk_var(false)); | ||||
|         scoped_anum num(am); | ||||
|         am.set(num, i + 1); | ||||
|         as.set(num_lo + i, num); | ||||
|     } | ||||
|     nlsat::var _z = s.mk_var(false); | ||||
|     nlsat::var _x = s.mk_var(false); | ||||
|     polynomial_ref x(pm), z(pm); | ||||
|     x = pm.mk_polynomial(_x); | ||||
|     scoped_anum val(am); | ||||
|     am.set(val, 0); | ||||
|     as.set(num_lo + num_hi, val); | ||||
|     as.set(num_lo + num_hi + 1, val); | ||||
|     s.set_rvalues(as); | ||||
|     nlsat::scoped_literal_vector lits(s); | ||||
| 
 | ||||
|     for (int i = 0; i < num_lo; ++i) { | ||||
|         polynomial_ref y(pm); | ||||
|         y = pm.mk_polynomial(los[i]); | ||||
|         lits.push_back(mk_gt(s, x - y)); | ||||
|     } | ||||
|     for (int i = 0; i < num_hi; ++i) { | ||||
|         polynomial_ref y(pm); | ||||
|         y = pm.mk_polynomial(his[i]); | ||||
|         lits.push_back(mk_gt(s, y - x)); | ||||
|     } | ||||
|     z = pm.mk_polynomial(_z); | ||||
|     lits.push_back(mk_eq(s, x - z)); | ||||
| 
 | ||||
| #define TEST_ON_OFF()                                   \ | ||||
|     std::cout << "Off ";                                \ | ||||
|     ex.set_signed_project(false);                       \ | ||||
|     project(s, ex, _x, lits.size()-1, lits.c_ptr());    \ | ||||
|     std::cout << "On ";                                 \ | ||||
|     ex.set_signed_project(true);                        \ | ||||
|     project(s, ex, _x, lits.size()-1, lits.c_ptr());    \ | ||||
|     std::cout << "Off ";                                \ | ||||
|     ex.set_signed_project(false);                       \ | ||||
|     project(s, ex, _x, lits.size(), lits.c_ptr());      \ | ||||
|     std::cout << "On ";                                 \ | ||||
|     ex.set_signed_project(true);                        \ | ||||
|     project(s, ex, _x, lits.size(), lits.c_ptr())       \ | ||||
| 
 | ||||
|     TEST_ON_OFF(); | ||||
| 
 | ||||
|     lits.reset(); | ||||
|     polynomial_ref u(pm); | ||||
|     u = pm.mk_polynomial(his[1]); | ||||
|     for (int i = 0; i < num_lo; ++i) { | ||||
|         polynomial_ref y(pm); | ||||
|         y = pm.mk_polynomial(los[i]); | ||||
|         lits.push_back(mk_gt(s, u*x - y)); | ||||
|     } | ||||
|     for (int i = 0; i < num_hi; ++i) { | ||||
|         polynomial_ref y(pm); | ||||
|         y = pm.mk_polynomial(his[i]); | ||||
|         lits.push_back(mk_gt(s, y - u*x)); | ||||
|     } | ||||
|     z = pm.mk_polynomial(_z); | ||||
|     lits.push_back(mk_eq(s, u*x - z)); | ||||
| 
 | ||||
|     TEST_ON_OFF(); | ||||
| 
 | ||||
|     lits.reset(); | ||||
|     u = pm.mk_polynomial(los[1]); | ||||
|     for (int i = 0; i < num_lo; ++i) { | ||||
|         polynomial_ref y(pm); | ||||
|         y = pm.mk_polynomial(los[i]); | ||||
|         lits.push_back(mk_gt(s, u*x - y)); | ||||
|     } | ||||
|     for (int i = 0; i < num_hi; ++i) { | ||||
|         polynomial_ref y(pm); | ||||
|         y = pm.mk_polynomial(his[i]); | ||||
|         lits.push_back(mk_gt(s, y - u*x)); | ||||
|     } | ||||
|     z = pm.mk_polynomial(_z); | ||||
|     lits.push_back(mk_eq(s, x - z)); | ||||
| 
 | ||||
|     TEST_ON_OFF(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #if 0 | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| static void test_root_literal(nlsat::solver& s, nlsat::explain& ex, nlsat::var x, nlsat::atom::kind k, unsigned i, nlsat::poly* p) { | ||||
|     nlsat::scoped_literal_vector result(s); | ||||
|     ex.test_root_literal(k, x, 1, p, result); | ||||
|     nlsat::bool_var b = s.mk_root_atom(k, x, i, p); | ||||
|     s.display(std::cout, nlsat::literal(b, false)); | ||||
|     s.display(std::cout << " ==> ", result.size(), result.c_ptr()); | ||||
|     std::cout << "\n"; | ||||
| } | ||||
| 
 | ||||
| static bool satisfies_root(nlsat::solver& s, nlsat::atom::kind k, nlsat::poly* p) { | ||||
|     nlsat::pmanager & pm  = s.pm(); | ||||
|     anum_manager & am     = s.am(); | ||||
|     nlsat::assignment as(am); | ||||
|     s.get_rvalues(as); | ||||
|     polynomial_ref pr(p, pm); | ||||
|     switch (k) { | ||||
|     case nlsat::atom::ROOT_EQ: return am.eval_sign_at(pr, as) == 0;  | ||||
|     case nlsat::atom::ROOT_LE: return am.eval_sign_at(pr, as) <= 0; | ||||
|     case nlsat::atom::ROOT_LT: return am.eval_sign_at(pr, as) <  0; | ||||
|     case nlsat::atom::ROOT_GE: return am.eval_sign_at(pr, as) >= 0; | ||||
|     case nlsat::atom::ROOT_GT: return am.eval_sign_at(pr, as) >  0; | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void tst10() { | ||||
|     params_ref      ps; | ||||
|     reslimit        rlim; | ||||
|     nlsat::solver s(rlim, ps); | ||||
|     anum_manager & am     = s.am(); | ||||
|     nlsat::pmanager & pm  = s.pm(); | ||||
|     nlsat::assignment as(am); | ||||
|     nlsat::explain& ex    = s.get_explain(); | ||||
|     nlsat::var _a = s.mk_var(false); | ||||
|     nlsat::var _b = s.mk_var(false); | ||||
|     nlsat::var _c = s.mk_var(false); | ||||
|     nlsat::var _x = s.mk_var(false); | ||||
| 
 | ||||
|     polynomial_ref x(pm), a(pm), b(pm), c(pm), p(pm); | ||||
|     x = pm.mk_polynomial(_x); | ||||
|     a = pm.mk_polynomial(_a); | ||||
|     b = pm.mk_polynomial(_b); | ||||
|     c = pm.mk_polynomial(_c); | ||||
|     p = a*x*x + b*x + c; | ||||
|     scoped_anum one(am), two(am), three(am), mone(am), mtwo(am), mthree(am), zero(am), one_a_half(am); | ||||
|     am.set(zero, 0); | ||||
|     am.set(one, 1); | ||||
|     am.set(two, 2); | ||||
|     am.set(three, 3); | ||||
|     am.set(mone, -1); | ||||
|     am.set(mtwo, -2); | ||||
|     am.set(mthree, -3); | ||||
|     rational oah(1,2); | ||||
|     am.set(one_a_half, oah.to_mpq()); | ||||
|      | ||||
|   | ||||
|     scoped_anum_vector nums(am); | ||||
|     nums.push_back(one); | ||||
|     nums.push_back(two); | ||||
|     nums.push_back(one_a_half); | ||||
|     nums.push_back(mone); | ||||
|     nums.push_back(three); | ||||
| 
 | ||||
|     // a = 1, b = -3, c = 2: 
 | ||||
|     // has roots x = 2, x = 1:
 | ||||
|     //  2^2 - 3*2 + 2 = 0
 | ||||
|     //  1 - 3 + 2 = 0
 | ||||
|     as.set(_a, one); | ||||
|     as.set(_b, mthree); | ||||
|     as.set(_c, two); | ||||
| 
 | ||||
|     for (unsigned i = 0; i < nums.size(); ++i) { | ||||
|         as.set(_x, nums[i]); | ||||
|         s.set_rvalues(as); | ||||
|         std::cout << p << "\n"; | ||||
|         as.display(std::cout); | ||||
|         for (unsigned k = nlsat::atom::ROOT_EQ; k <= nlsat::atom::ROOT_GE; ++k) { | ||||
|             if (satisfies_root(s, (nlsat::atom::kind) k, p)) { | ||||
|                 test_root_literal(s, ex, _x, (nlsat::atom::kind) k, 1, p); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     as.set(_a, mone); | ||||
|     as.set(_b, three); | ||||
|     as.set(_c, mtwo); | ||||
|     for (unsigned i = 0; i < nums.size(); ++i) { | ||||
|         as.set(_x, nums[i]); | ||||
|         s.set_rvalues(as); | ||||
|         std::cout << p << "\n"; | ||||
|         as.display(std::cout); | ||||
|         for (unsigned k = nlsat::atom::ROOT_EQ; k <= nlsat::atom::ROOT_GE; ++k) { | ||||
|             if (satisfies_root(s, (nlsat::atom::kind) k, p)) { | ||||
|                 test_root_literal(s, ex, _x, (nlsat::atom::kind) k, 1, p); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     std::cout << "\n"; | ||||
| } | ||||
| 
 | ||||
| void tst_nlsat() { | ||||
|     tst10(); | ||||
|     std::cout << "------------------\n"; | ||||
|     exit(0); | ||||
|     tst9(); | ||||
|     std::cout << "------------------\n"; | ||||
|     exit(0); | ||||
|     tst8(); | ||||
|     std::cout << "------------------\n"; | ||||
|     tst7(); | ||||
|     std::cout << "------------------\n"; | ||||
|     tst6(); | ||||
|     std::cout << "------------------\n"; | ||||
|     tst5(); | ||||
|     std::cout << "------------------\n"; | ||||
|     tst4(); | ||||
|     std::cout << "------------------\n"; | ||||
|     tst3(); | ||||
| } | ||||
|  |  | |||
|  | @ -12,9 +12,9 @@ Copyright (c) 2015 Microsoft Corporation | |||
| #include "reg_decl_plugins.h" | ||||
| #include "arith_rewriter.h" | ||||
| #include "ast_pp.h" | ||||
| #include "qe_util.h" | ||||
| #include "smt_context.h" | ||||
| #include "expr_abstract.h" | ||||
| #include "expr_safe_replace.h" | ||||
| 
 | ||||
| static expr_ref parse_fml(ast_manager& m, char const* str) { | ||||
|     expr_ref result(m); | ||||
|  | @ -29,6 +29,11 @@ static expr_ref parse_fml(ast_manager& m, char const* str) { | |||
|            << "(declare-const t Real)\n" | ||||
|            << "(declare-const a Real)\n" | ||||
|            << "(declare-const b Real)\n" | ||||
|            << "(declare-const i Int)\n" | ||||
|            << "(declare-const j Int)\n" | ||||
|            << "(declare-const k Int)\n" | ||||
|            << "(declare-const l Int)\n" | ||||
|            << "(declare-const m Int)\n" | ||||
|            << "(assert " << str << ")\n"; | ||||
|     std::istringstream is(buffer.str()); | ||||
|     VERIFY(parse_smt2_commands(ctx, is)); | ||||
|  | @ -42,6 +47,8 @@ static char const* example2 = "(and (<= z x) (<= x 3.0) (<= (* 3.0 x) y) (<= z y | |||
| static char const* example3 = "(and (<= z x) (<= x 3.0) (< (* 3.0 x) y) (<= z y))"; | ||||
| static char const* example4 = "(and (<= z x) (<= x 3.0) (not (>= (* 3.0 x) y)) (<= z y))"; | ||||
| static char const* example5 = "(and (<= y x) (<= z x) (<= x u) (<= x v) (<= x t))"; | ||||
| static char const* example7 = "(and (<= x y) (<= x z) (<= u x) (< v x))"; | ||||
| static char const* example8 = "(and  (<= (* 2 i) k) (<= j (* 3 i)))"; | ||||
| 
 | ||||
| static char const* example6 = "(and (<= 0 (+ x z))\
 | ||||
|      (>= y x) \ | ||||
|  | @ -51,30 +58,175 @@ static char const* example6 = "(and (<= 0 (+ x z))\ | |||
|      (>= x 0.0)\ | ||||
|      (<= x 1.0))"; | ||||
| 
 | ||||
| // phi[M] => result => E x . phi[x] 
 | ||||
| 
 | ||||
| static void test(char const *ex) { | ||||
| static void test(app* var, expr_ref& fml) { | ||||
| 
 | ||||
|     ast_manager& m = fml.get_manager(); | ||||
|     smt_params params; | ||||
|     params.m_model = true; | ||||
| 
 | ||||
|     symbol x_name(var->get_decl()->get_name());    | ||||
|     sort* x_sort = m.get_sort(var); | ||||
| 
 | ||||
|     expr_ref pr(m); | ||||
|     expr_ref_vector lits(m); | ||||
|     flatten_and(fml, lits); | ||||
| 
 | ||||
|     model_ref md; | ||||
|     { | ||||
|         smt::context ctx(m, params); | ||||
|         ctx.assert_expr(fml); | ||||
|         lbool result = ctx.check(); | ||||
|         if (result != l_true) return; | ||||
|         ctx.get_model(md); | ||||
|     }     | ||||
|     VERIFY(qe::arith_project(*md, var, lits)); | ||||
|     pr = mk_and(lits); | ||||
|     | ||||
|     std::cout << "original:  " << mk_pp(fml, m) << "\n"; | ||||
|     std::cout << "projected: " << mk_pp(pr,  m) << "\n"; | ||||
| 
 | ||||
|     // projection is consistent with model.
 | ||||
|     expr_ref tmp(m); | ||||
|     VERIFY(md->eval(pr, tmp) && m.is_true(tmp));        | ||||
| 
 | ||||
|     // projection implies E x. fml
 | ||||
|     { | ||||
|         qe::expr_quant_elim qelim(m, params); | ||||
|         expr_ref result(m), efml(m); | ||||
|         expr* x = var; | ||||
|         expr_abstract(m, 0, 1, &x, fml, efml); | ||||
|         efml = m.mk_exists(1, &x_sort, &x_name, efml); | ||||
|         qelim(m.mk_true(), efml, result); | ||||
| 
 | ||||
|         smt::context ctx(m, params); | ||||
|         ctx.assert_expr(pr); | ||||
|         ctx.assert_expr(m.mk_not(result)); | ||||
|         std::cout << "exists: " << pr << " =>\n" << result << "\n"; | ||||
|         VERIFY(l_false == ctx.check()); | ||||
|     }     | ||||
| 
 | ||||
|     std::cout << "\n"; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static void testR(char const *ex) { | ||||
|     ast_manager m; | ||||
|     reg_decl_plugins(m); | ||||
|     arith_util a(m); | ||||
|     expr_ref fml = parse_fml(m, ex); | ||||
|     app_ref_vector vars(m); | ||||
|     expr_ref_vector lits(m); | ||||
|     vars.push_back(m.mk_const(symbol("x"), a.mk_real())); | ||||
|     flatten_and(fml, lits); | ||||
|     symbol x_name("x"); | ||||
|     sort_ref x_sort(a.mk_real(), m); | ||||
|     app_ref var(m.mk_const(x_name, x_sort), m); | ||||
|     test(var, fml); | ||||
| } | ||||
| 
 | ||||
|     smt::context ctx(m, params); | ||||
|     ctx.assert_expr(fml); | ||||
|     lbool result = ctx.check(); | ||||
|     SASSERT(result == l_true); | ||||
|     ref<model> md; | ||||
|     ctx.get_model(md);     | ||||
|     expr_ref pr = qe::arith_project(*md, vars, lits); | ||||
|      | ||||
|     std::cout << mk_pp(fml, m) << "\n"; | ||||
|     std::cout << mk_pp(pr, m) << "\n"; | ||||
| static void testI(char const *ex) { | ||||
|     ast_manager m; | ||||
|     reg_decl_plugins(m); | ||||
|     arith_util a(m); | ||||
|     expr_ref fml = parse_fml(m, ex); | ||||
|     symbol x_name("i"); | ||||
|     sort_ref x_sort(a.mk_int(), m); | ||||
|     app_ref var(m.mk_const(x_name, x_sort), m); | ||||
|     test(var, fml); | ||||
| } | ||||
| 
 | ||||
| static expr_ref_vector mk_ineqs(app* x, app* y, app_ref_vector const& nums) { | ||||
|     ast_manager& m = nums.get_manager(); | ||||
|     arith_util a(m); | ||||
|     expr_ref_vector result(m); | ||||
|     for (unsigned i = 0; i < nums.size(); ++i) { | ||||
|         expr_ref ax(a.mk_mul(nums[i], x), m); | ||||
|         result.push_back(a.mk_le(ax, y)); | ||||
|         result.push_back(m.mk_not(a.mk_ge(ax, y))); | ||||
|         result.push_back(m.mk_not(a.mk_gt(y, ax))); | ||||
|         result.push_back(a.mk_lt(y, ax)); | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| static app_ref generate_ineqs(ast_manager& m, sort* s, vector<expr_ref_vector>& cs, bool mods_too) { | ||||
|     arith_util a(m); | ||||
|     app_ref_vector vars(m), nums(m); | ||||
|     vars.push_back(m.mk_const(symbol("x"), s)); | ||||
|     vars.push_back(m.mk_const(symbol("y"), s)); | ||||
|     vars.push_back(m.mk_const(symbol("z"), s)); | ||||
|     vars.push_back(m.mk_const(symbol("u"), s)); | ||||
|     vars.push_back(m.mk_const(symbol("v"), s)); | ||||
|     vars.push_back(m.mk_const(symbol("w"), s)); | ||||
|     nums.push_back(a.mk_numeral(rational(1),  s)); | ||||
|     nums.push_back(a.mk_numeral(rational(2),  s)); | ||||
|     nums.push_back(a.mk_numeral(rational(3),  s)); | ||||
|      | ||||
|     app* x = vars[0].get(); | ||||
|     app* y = vars[1].get(); | ||||
|     app* z = vars[2].get(); | ||||
|     // 
 | ||||
|     // ax <= by, ax < by, not (ax >= by), not (ax > by)
 | ||||
|     // 
 | ||||
|     cs.push_back(mk_ineqs(x, vars[1].get(), nums)); | ||||
|     cs.push_back(mk_ineqs(x, vars[2].get(), nums)); | ||||
|     cs.push_back(mk_ineqs(x, vars[3].get(), nums)); | ||||
|     cs.push_back(mk_ineqs(x, vars[4].get(), nums)); | ||||
|     cs.push_back(mk_ineqs(x, vars[5].get(), nums)); | ||||
| 
 | ||||
|     if (mods_too) { | ||||
|         expr_ref_vector mods(m); | ||||
|         expr_ref zero(a.mk_numeral(rational(0), s), m); | ||||
|         mods.push_back(m.mk_true()); | ||||
|         for (unsigned j = 0; j < nums.size(); ++j) { | ||||
|             mods.push_back(m.mk_eq(a.mk_mod(a.mk_add(a.mk_mul(nums[j].get(),x), y), nums[1].get()), zero)); | ||||
|         } | ||||
|         cs.push_back(mods); | ||||
|         mods.resize(1); | ||||
|         for (unsigned j = 0; j < nums.size(); ++j) { | ||||
|             mods.push_back(m.mk_eq(a.mk_mod(a.mk_add(a.mk_mul(nums[j].get(),x), y), nums[2].get()), zero)); | ||||
|         } | ||||
|         cs.push_back(mods); | ||||
|     } | ||||
|     return app_ref(x, m); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void test_c(app* x, expr_ref_vector const& c) { | ||||
|     ast_manager& m = c.get_manager(); | ||||
|     expr_ref fml(m); | ||||
|     fml = m.mk_and(c.size(), c.c_ptr()); | ||||
|     test(x, fml); | ||||
| } | ||||
| 
 | ||||
| static void test_cs(app* x, expr_ref_vector& c, vector<expr_ref_vector> const& cs) { | ||||
|     if (c.size() == cs.size()) { | ||||
|         test_c(x, c); | ||||
|         return; | ||||
|     } | ||||
|     expr_ref_vector const& c1 = cs[c.size()]; | ||||
|     for (unsigned i = 0; i < c1.size(); ++i) { | ||||
|         c.push_back(c1[i]); | ||||
|         test_cs(x, c, cs); | ||||
|         c.pop_back(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void test_ineqs(ast_manager& m, sort* s, bool mods_too) { | ||||
|     vector<expr_ref_vector> ineqs; | ||||
|     app_ref x = generate_ineqs(m, s, ineqs, mods_too); | ||||
|     expr_ref_vector cs(m); | ||||
|     test_cs(x, cs, ineqs); | ||||
| } | ||||
| 
 | ||||
| static void test_ineqs() { | ||||
|     ast_manager m; | ||||
|     reg_decl_plugins(m); | ||||
|     arith_util a(m); | ||||
|     sort* s_int = a.mk_int(); | ||||
|     sort* s_real = a.mk_real(); | ||||
|     test_ineqs(m, s_int, true); | ||||
|     test_ineqs(m, s_real, false); | ||||
| } | ||||
| 
 | ||||
| static void test2(char const *ex) { | ||||
|  | @ -102,7 +254,7 @@ static void test2(char const *ex) { | |||
|      | ||||
|     std::cout << mk_pp(fml, m) << "\n"; | ||||
| 
 | ||||
|     expr_ref pr2(m), fml2(m); | ||||
|     expr_ref pr1(m), pr2(m), fml2(m); | ||||
|     expr_ref_vector bound(m); | ||||
|     ptr_vector<sort> sorts; | ||||
|     svector<symbol> names; | ||||
|  | @ -114,7 +266,10 @@ static void test2(char const *ex) { | |||
|     expr_abstract(m, 0, bound.size(), bound.c_ptr(), fml, fml2); | ||||
|     fml2 = m.mk_exists(bound.size(), sorts.c_ptr(), names.c_ptr(), fml2); | ||||
|     qe::expr_quant_elim qe(m, params); | ||||
|     expr_ref pr1 = qe::arith_project(*md, vars, lits); | ||||
|     for (unsigned i = 0; i < vars.size(); ++i) { | ||||
|         VERIFY(qe::arith_project(*md, vars[i].get(), lits)); | ||||
|     } | ||||
|     pr1 = mk_and(lits); | ||||
|     qe(m.mk_true(), fml2, pr2); | ||||
|     std::cout << mk_pp(pr1, m) << "\n"; | ||||
|     std::cout << mk_pp(pr2, m) << "\n"; | ||||
|  | @ -131,11 +286,17 @@ static void test2(char const *ex) { | |||
| } | ||||
| 
 | ||||
| void tst_qe_arith() { | ||||
| //    enable_trace("qe");
 | ||||
|     testI(example8);     | ||||
|     testR(example7); | ||||
|     test_ineqs(); | ||||
|     return; | ||||
|     testR(example1); | ||||
|     testR(example2); | ||||
|     testR(example3); | ||||
|     testR(example4); | ||||
|     testR(example5); | ||||
|     return; | ||||
|     test2(example6); | ||||
|     return; | ||||
|     test(example1); | ||||
|     test(example2); | ||||
|     test(example3); | ||||
|     test(example4); | ||||
|     test(example5); | ||||
| } | ||||
|  |  | |||
|  | @ -45,6 +45,7 @@ public: | |||
|     bool contains(T1 * t1, T2 * t2) const { return m_set.contains(obj_pair(t1, t2)); } | ||||
|     bool contains(obj_pair const & p) const { return m_set.contains(p); } | ||||
|     void reset() { m_set.reset(); } | ||||
|     bool empty() const { return m_set.empty(); } | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -69,6 +69,7 @@ void small_object_allocator::reset() { | |||
| #define MASK ((1 << PTR_ALIGNMENT) - 1) | ||||
| 
 | ||||
| void small_object_allocator::deallocate(size_t size, void * p) { | ||||
|     if (size == 0) return; | ||||
| #if defined(Z3DEBUG) && !defined(_WINDOWS) | ||||
|     // Valgrind friendly
 | ||||
|     memory::deallocate(p); | ||||
|  | @ -91,6 +92,7 @@ void small_object_allocator::deallocate(size_t size, void * p) { | |||
| } | ||||
| 
 | ||||
| void * small_object_allocator::allocate(size_t size) { | ||||
|     if (size == 0) return 0; | ||||
| #if defined(Z3DEBUG) && !defined(_WINDOWS) | ||||
|     // Valgrind friendly
 | ||||
|     return memory::allocate(size); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue