mirror of
https://github.com/Z3Prover/z3
synced 2025-04-28 11:25:51 +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
|
# Tracing
|
||||||
################################################################################
|
################################################################################
|
||||||
option(ENABLE_TRACING OFF "Enable tracing")
|
option(ENABLE_TRACING_FOR_NON_DEBUG "Enable tracing in non-debug builds." OFF)
|
||||||
if (ENABLE_TRACING)
|
if (ENABLE_TRACING_FOR_NON_DEBUG)
|
||||||
list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_TRACE")
|
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()
|
endif()
|
||||||
# Should we always enable tracing when doing a debug build?
|
# Should we always enable tracing when doing a debug build?
|
||||||
#list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:_TRACE>)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Postion indepdent code
|
# 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_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_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/``).
|
* ``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.
|
* ``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.
|
* ``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.
|
* ``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)
|
option(INSTALL_PYTHON_BINDINGS "Install Python bindings when invoking install target" ON)
|
||||||
if (INSTALL_PYTHON_BINDINGS)
|
if (INSTALL_PYTHON_BINDINGS)
|
||||||
# Determine the installation path for the bindings
|
|
||||||
message(STATUS "Emitting rules to install Z3 python bindings")
|
message(STATUS "Emitting rules to install Z3 python bindings")
|
||||||
execute_process(
|
# Try to guess the installation path for the bindings
|
||||||
COMMAND "${PYTHON_EXECUTABLE}" "-c"
|
if (NOT DEFINED CMAKE_INSTALL_PYTHON_PKG_DIR)
|
||||||
"import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())"
|
message(STATUS "CMAKE_INSTALL_PYTHON_PKG_DIR not set. Trying to guess")
|
||||||
RESULT_VARIABLE exit_code
|
execute_process(
|
||||||
OUTPUT_VARIABLE python_pkg_dir
|
COMMAND "${PYTHON_EXECUTABLE}" "-c"
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
"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))
|
if (NOT ("${exit_code}" EQUAL 0))
|
||||||
message(FATAL_ERROR "Failed to determine your Python package directory")
|
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()
|
endif()
|
||||||
message(STATUS "Detected Python package directory: \"${python_pkg_dir}\"")
|
|
||||||
|
|
||||||
# Check if path exists under the install prefix
|
# Check if path exists under the install prefix if it is absolute. If the
|
||||||
set(python_install_dir "")
|
# path is relative it will be installed under the install prefix so there
|
||||||
string(FIND "${python_pkg_dir}" "${CMAKE_INSTALL_PREFIX}" position)
|
# if nothing to check
|
||||||
if (NOT ("${position}" EQUAL 0))
|
if (IS_ABSOLUTE "${CMAKE_INSTALL_PYTHON_PKG_DIR}")
|
||||||
message(WARNING "The detected Python package directory \"${python_pkg_dir}\" "
|
string(FIND "${CMAKE_INSTALL_PYTHON_PKG_DIR}" "${CMAKE_INSTALL_PREFIX}" position)
|
||||||
"does not exist under the install prefix \"${CMAKE_INSTALL_PREFIX}\"."
|
if (NOT ("${position}" EQUAL 0))
|
||||||
" Running the install target may lead to a broken installation."
|
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()
|
endif()
|
||||||
# Using DESTDIR still seems to work even if we use an absolute path
|
# 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 \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\"")
|
||||||
message(STATUS "Python bindings will be installed to \"${python_install_dir}\"")
|
|
||||||
install(FILES ${build_z3_python_bindings_target_depends}
|
install(FILES ${build_z3_python_bindings_target_depends}
|
||||||
DESTINATION "${python_install_dir}"
|
DESTINATION "${CMAKE_INSTALL_PYTHON_PKG_DIR}"
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
message(STATUS "Not emitting rules to install Z3 python bindings")
|
message(STATUS "Not emitting rules to install Z3 python bindings")
|
||||||
|
|
|
@ -12,6 +12,7 @@ z3_add_component(rewriter
|
||||||
expr_safe_replace.cpp
|
expr_safe_replace.cpp
|
||||||
factor_rewriter.cpp
|
factor_rewriter.cpp
|
||||||
fpa_rewriter.cpp
|
fpa_rewriter.cpp
|
||||||
|
label_rewriter.cpp
|
||||||
mk_simplified_app.cpp
|
mk_simplified_app.cpp
|
||||||
pb_rewriter.cpp
|
pb_rewriter.cpp
|
||||||
quant_hoist.cpp
|
quant_hoist.cpp
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
z3_add_component(qe
|
z3_add_component(qe
|
||||||
SOURCES
|
SOURCES
|
||||||
nlarith_util.cpp
|
nlarith_util.cpp
|
||||||
|
nlqsat.cpp
|
||||||
qe_arith.cpp
|
qe_arith.cpp
|
||||||
qe_arith_plugin.cpp
|
qe_arith_plugin.cpp
|
||||||
qe_array_plugin.cpp
|
qe_array_plugin.cpp
|
||||||
|
qe_arrays.cpp
|
||||||
qe_bool_plugin.cpp
|
qe_bool_plugin.cpp
|
||||||
qe_bv_plugin.cpp
|
qe_bv_plugin.cpp
|
||||||
qe_cmd.cpp
|
qe_cmd.cpp
|
||||||
qe.cpp
|
qe.cpp
|
||||||
qe_datatype_plugin.cpp
|
qe_datatype_plugin.cpp
|
||||||
|
qe_datatypes.cpp
|
||||||
qe_dl_plugin.cpp
|
qe_dl_plugin.cpp
|
||||||
qe_lite.cpp
|
qe_lite.cpp
|
||||||
|
qe_mbp.cpp
|
||||||
qe_sat_tactic.cpp
|
qe_sat_tactic.cpp
|
||||||
qe_tactic.cpp
|
qe_tactic.cpp
|
||||||
qe_util.cpp
|
qsat.cpp
|
||||||
vsubst_tactic.cpp
|
vsubst_tactic.cpp
|
||||||
COMPONENT_DEPENDENCIES
|
COMPONENT_DEPENDENCIES
|
||||||
|
nlsat_tactic
|
||||||
|
nlsat
|
||||||
sat
|
sat
|
||||||
smt
|
smt
|
||||||
|
tactic
|
||||||
)
|
)
|
||||||
|
|
|
@ -57,7 +57,7 @@ def sorted_headers_by_component(l):
|
||||||
_logger.debug("get_key({})".format(path))
|
_logger.debug("get_key({})".format(path))
|
||||||
path_components = []
|
path_components = []
|
||||||
stripped_path = path
|
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``
|
# Keep stripping off directory components until we hit ``src``
|
||||||
while os.path.basename(stripped_path) != 'src':
|
while os.path.basename(stripped_path) != 'src':
|
||||||
path_components.append(os.path.basename(stripped_path))
|
path_components.append(os.path.basename(stripped_path))
|
||||||
|
|
|
@ -57,7 +57,7 @@ def init_project_def():
|
||||||
add_lib('fuzzing', ['ast'], 'test/fuzzing')
|
add_lib('fuzzing', ['ast'], 'test/fuzzing')
|
||||||
add_lib('smt_tactic', ['smt'], 'smt/tactic')
|
add_lib('smt_tactic', ['smt'], 'smt/tactic')
|
||||||
add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls')
|
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('duality', ['smt', 'interp', 'qe'])
|
||||||
add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base')
|
add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base')
|
||||||
add_lib('dataflow', ['muz'], 'muz/dataflow')
|
add_lib('dataflow', ['muz'], 'muz/dataflow')
|
||||||
|
|
|
@ -604,8 +604,16 @@ namespace z3 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return true if this expression is a numeral.
|
\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() 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.
|
\brief Return true if this expression is an application.
|
||||||
*/
|
*/
|
||||||
|
@ -625,7 +633,7 @@ namespace z3 {
|
||||||
/**
|
/**
|
||||||
\brief Return true if expression is an algebraic number.
|
\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).
|
\brief Return true if this expression is well sorted (aka type correct).
|
||||||
|
@ -650,11 +658,10 @@ namespace z3 {
|
||||||
\pre is_numeral()
|
\pre is_numeral()
|
||||||
*/
|
*/
|
||||||
int get_numeral_int() const {
|
int get_numeral_int() const {
|
||||||
assert(is_numeral());
|
|
||||||
int result;
|
int result;
|
||||||
Z3_bool state = Z3_get_numeral_int(ctx(), m_ast, &result);
|
if (!is_numeral_i(result)) {
|
||||||
if (state != Z3_TRUE)
|
|
||||||
throw exception("numeral does not fit in machine int");
|
throw exception("numeral does not fit in machine int");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,9 +674,9 @@ namespace z3 {
|
||||||
unsigned get_numeral_uint() const {
|
unsigned get_numeral_uint() const {
|
||||||
assert(is_numeral());
|
assert(is_numeral());
|
||||||
unsigned result;
|
unsigned result;
|
||||||
Z3_bool state = Z3_get_numeral_uint(ctx(), m_ast, &result);
|
if (!is_numeral_u(result)) {
|
||||||
if (state != Z3_TRUE)
|
|
||||||
throw exception("numeral does not fit in machine uint");
|
throw exception("numeral does not fit in machine uint");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,9 +689,9 @@ namespace z3 {
|
||||||
__int64 get_numeral_int64() const {
|
__int64 get_numeral_int64() const {
|
||||||
assert(is_numeral());
|
assert(is_numeral());
|
||||||
__int64 result;
|
__int64 result;
|
||||||
Z3_bool state = Z3_get_numeral_int64(ctx(), m_ast, &result);
|
if (!is_numeral_i64(result)) {
|
||||||
if (state != Z3_TRUE)
|
|
||||||
throw exception("numeral does not fit in machine __int64");
|
throw exception("numeral does not fit in machine __int64");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,9 +704,9 @@ namespace z3 {
|
||||||
__uint64 get_numeral_uint64() const {
|
__uint64 get_numeral_uint64() const {
|
||||||
assert(is_numeral());
|
assert(is_numeral());
|
||||||
__uint64 result;
|
__uint64 result;
|
||||||
Z3_bool state = Z3_get_numeral_uint64(ctx(), m_ast, &result);
|
if (!is_numeral_u64(result)) {
|
||||||
if (state != Z3_TRUE)
|
|
||||||
throw exception("numeral does not fit in machine __uint64");
|
throw exception("numeral does not fit in machine __uint64");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4162,6 +4162,7 @@ def Select(a, i):
|
||||||
_z3_assert(is_array(a), "First argument must be a Z3 array expression")
|
_z3_assert(is_array(a), "First argument must be a Z3 array expression")
|
||||||
return a[i]
|
return a[i]
|
||||||
|
|
||||||
|
|
||||||
def Map(f, *args):
|
def Map(f, *args):
|
||||||
"""Return a Z3 map array expression.
|
"""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));
|
SASSERT(is_irrational_algebraic_numeral(n));
|
||||||
return plugin().aw().to_anum(to_app(n)->get_decl());
|
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_mod_0_decl;
|
||||||
func_decl * m_u_asin_decl;
|
func_decl * m_u_asin_decl;
|
||||||
func_decl * m_u_acos_decl;
|
func_decl * m_u_acos_decl;
|
||||||
|
|
||||||
ptr_vector<app> m_small_ints;
|
ptr_vector<app> m_small_ints;
|
||||||
ptr_vector<app> m_small_reals;
|
ptr_vector<app> m_small_reals;
|
||||||
|
|
||||||
|
@ -416,6 +415,11 @@ public:
|
||||||
return m_manager.mk_eq(lhs, rhs);
|
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_ */
|
#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());
|
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) {
|
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) {
|
||||||
for (unsigned i = 0; i < e.size(); ++i) {
|
for (unsigned i = 0; i < e.size(); ++i) {
|
||||||
out << mk_ismt2_pp(e[i], e.get_manager());
|
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;
|
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
|
#ifdef Z3DEBUG
|
||||||
void pp(expr const * n, ast_manager & m) {
|
void pp(expr const * n, ast_manager & m) {
|
||||||
std::cout << mk_ismt2_pp(const_cast<expr*>(n), m) << std::endl;
|
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, expr_ref const& e);
|
||||||
std::ostream& operator<<(std::ostream& out, app_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, expr_ref_vector const& e);
|
||||||
std::ostream& operator<<(std::ostream& out, app_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
|
#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));
|
return to_app(mk_and(m, num_args, (expr* const*) args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) {
|
expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) {
|
||||||
if (num_args == 0)
|
if (num_args == 0)
|
||||||
return m.mk_false();
|
return m.mk_false();
|
||||||
|
@ -188,10 +187,43 @@ expr * mk_not(ast_manager & m, expr * arg) {
|
||||||
expr * atom;
|
expr * atom;
|
||||||
if (m.is_not(arg, atom))
|
if (m.is_not(arg, atom))
|
||||||
return atom;
|
return atom;
|
||||||
|
else if (m.is_true(arg))
|
||||||
|
return m.mk_false();
|
||||||
|
else if (m.is_false(arg))
|
||||||
|
return m.mk_true();
|
||||||
else
|
else
|
||||||
return m.mk_not(arg);
|
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 * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args) {
|
||||||
expr_ref_buffer new_diseqs(m);
|
expr_ref_buffer new_diseqs(m);
|
||||||
for (unsigned i = 0; i < num_args; i++) {
|
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());
|
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) {
|
void flatten_and(expr_ref_vector& result) {
|
||||||
ast_manager& m = result.get_manager();
|
ast_manager& m = result.get_manager();
|
||||||
expr* e1, *e2, *e3;
|
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 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()); }
|
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)
|
Return a if arg = (not a)
|
||||||
Retur (not arg) otherwise
|
Retur (not arg) otherwise
|
||||||
*/
|
*/
|
||||||
expr * mk_not(ast_manager & m, expr * arg);
|
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])))
|
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);
|
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.
|
\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);
|
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) {
|
app * bv_util::mk_bv2int(expr* e) {
|
||||||
sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT);
|
sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT);
|
||||||
parameter p(s);
|
parameter p(s);
|
||||||
|
|
|
@ -234,7 +234,6 @@ protected:
|
||||||
|
|
||||||
func_decl * mk_mkbv(unsigned arity, sort * const * domain);
|
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);
|
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);
|
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) {
|
virtual bool is_considered_uninterpreted(func_decl * f) {
|
||||||
if (f->get_family_id() != get_family_id())
|
if (f->get_family_id() != get_family_id())
|
||||||
return false;
|
return false;
|
||||||
|
@ -390,6 +391,8 @@ public:
|
||||||
return static_cast<unsigned>(s->get_parameter(0).get_int());
|
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_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_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); }
|
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_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); }
|
app * mk_bv(unsigned n, expr* const* es) { return m_manager.mk_app(get_fid(), OP_MKBV, n, es); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* BV_DECL_PLUGIN_H_ */
|
#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);
|
func_decl * get_recognizer_constructor(func_decl * recognizer);
|
||||||
family_id get_family_id() const { return m_family_id; }
|
family_id get_family_id() const { return m_family_id; }
|
||||||
bool are_siblings(sort * s1, sort * s2);
|
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 reset();
|
||||||
void display_datatype(sort *s, std::ostream& strm);
|
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) {
|
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;
|
expr * curr = 0, *b = 0;
|
||||||
SASSERT(n->get_ref_count() > 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);
|
expr_abstractor abs(m);
|
||||||
abs(base, num_bound, bound, n, result);
|
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);
|
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
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,14 @@ void expr_safe_replace::insert(expr* src, expr* dst) {
|
||||||
m_subst.insert(src, 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) {
|
void expr_safe_replace::operator()(expr* e, expr_ref& res) {
|
||||||
m_todo.push_back(e);
|
m_todo.push_back(e);
|
||||||
expr* a, *b;
|
expr* a, *b;
|
||||||
|
|
|
@ -42,6 +42,8 @@ public:
|
||||||
|
|
||||||
void operator()(expr* src, expr_ref& e);
|
void operator()(expr* src, expr_ref& e);
|
||||||
|
|
||||||
|
void operator()(expr_ref_vector& es);
|
||||||
|
|
||||||
void apply_substitution(expr* s, expr* def, expr_ref& t);
|
void apply_substitution(expr* s, expr* def, expr_ref& t);
|
||||||
|
|
||||||
void reset();
|
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();
|
unsigned nd = q->get_num_decls();
|
||||||
for (unsigned i = 0; i < nd; ++i) {
|
for (unsigned i = 0; i < nd; ++i) {
|
||||||
sort* s = q->get_decl_sort(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);
|
vars.push_back(a);
|
||||||
}
|
}
|
||||||
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
|
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
|
||||||
|
@ -154,9 +154,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
quantifier_type& negate(quantifier_type& qt) {
|
quantifier_type& negate(quantifier_type& qt) {
|
||||||
TRACE("qe", display(qt, tout); tout << "\n";);
|
|
||||||
qt = static_cast<quantifier_type>(qt ^0x1);
|
qt = static_cast<quantifier_type>(qt ^0x1);
|
||||||
TRACE("qe", display(qt, tout); tout << "\n";);
|
|
||||||
return qt;
|
return qt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +203,7 @@ private:
|
||||||
case AST_APP: {
|
case AST_APP: {
|
||||||
expr_ref_vector args(m);
|
expr_ref_vector args(m);
|
||||||
expr_ref tmp(m);
|
expr_ref tmp(m);
|
||||||
|
expr* t1, *t2, *t3;
|
||||||
unsigned num_args = 0;
|
unsigned num_args = 0;
|
||||||
app* a = to_app(fml);
|
app* a = to_app(fml);
|
||||||
if (m.is_and(fml)) {
|
if (m.is_and(fml)) {
|
||||||
|
@ -228,16 +227,35 @@ private:
|
||||||
negate(qt);
|
negate(qt);
|
||||||
result = m.mk_not(tmp);
|
result = m.mk_not(tmp);
|
||||||
}
|
}
|
||||||
else if (m.is_implies(fml)) {
|
else if (m.is_implies(fml, t1, t2)) {
|
||||||
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
|
pull_quantifier(t1, negate(qt), vars, tmp);
|
||||||
negate(qt);
|
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);
|
result = m.mk_implies(tmp, result);
|
||||||
}
|
}
|
||||||
else if (m.is_ite(fml)) {
|
else if (m.is_ite(fml, t1, t2, t3)) {
|
||||||
pull_quantifier(to_app(fml)->get_arg(1), qt, vars, tmp);
|
expr_ref tt1(m), tt2(m), tt3(m), ntt1(m), nt1(m);
|
||||||
pull_quantifier(to_app(fml)->get_arg(2), qt, vars, result);
|
pull_quantifier(t2, qt, vars, tt2);
|
||||||
result = m.mk_ite(to_app(fml)->get_arg(0), tmp, result);
|
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 {
|
else {
|
||||||
// the formula contains a quantifier, but it is "inaccessible"
|
// the formula contains a quantifier, but it is "inaccessible"
|
||||||
|
|
|
@ -578,6 +578,16 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
||||||
return st;
|
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,
|
bool reduce_quantifier(quantifier * old_q,
|
||||||
expr * new_body,
|
expr * new_body,
|
||||||
expr * const * new_patterns,
|
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),
|
rewriter_tpl<th_rewriter_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||||
m_cfg(m, p) {
|
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):
|
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;
|
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 * t, expr_ref & result, proof_ref & result_pr);
|
||||||
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result);
|
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 cleanup();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
|
|
@ -303,8 +303,8 @@ public:
|
||||||
goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores());
|
goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores());
|
||||||
assert_exprs_from(ctx, *g);
|
assert_exprs_from(ctx, *g);
|
||||||
|
|
||||||
unsigned timeout = p.get_uint("timeout", UINT_MAX);
|
unsigned timeout = p.get_uint("timeout", ctx.params().m_timeout);
|
||||||
unsigned rlimit = p.get_uint("rlimit", 0);
|
unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit);
|
||||||
|
|
||||||
goal_ref_buffer result_goals;
|
goal_ref_buffer result_goals;
|
||||||
model_converter_ref mc;
|
model_converter_ref mc;
|
||||||
|
|
|
@ -539,7 +539,6 @@ namespace algebraic_numbers {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool factor(scoped_upoly const & up, factors & r) {
|
bool factor(scoped_upoly const & up, factors & r) {
|
||||||
// std::cout << "factor: "; upm().display(std::cout, up); std::cout << std::endl;
|
|
||||||
if (m_factor) {
|
if (m_factor) {
|
||||||
return upm().factor(up, r, m_factor_params);
|
return upm().factor(up, r, m_factor_params);
|
||||||
}
|
}
|
||||||
|
@ -547,7 +546,7 @@ namespace algebraic_numbers {
|
||||||
scoped_upoly & up_sqf = m_isolate_tmp3;
|
scoped_upoly & up_sqf = m_isolate_tmp3;
|
||||||
up_sqf.reset();
|
up_sqf.reset();
|
||||||
upm().square_free(up.size(), up.c_ptr(), up_sqf);
|
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);
|
r.push_back(up_sqf, 1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -566,6 +565,7 @@ namespace algebraic_numbers {
|
||||||
}
|
}
|
||||||
|
|
||||||
void isolate_roots(scoped_upoly const & up, numeral_vector & roots) {
|
void isolate_roots(scoped_upoly const & up, numeral_vector & roots) {
|
||||||
|
TRACE("algebraic", upm().display(tout, up); tout << "\n";);
|
||||||
if (up.empty())
|
if (up.empty())
|
||||||
return; // ignore the zero polynomial
|
return; // ignore the zero polynomial
|
||||||
factors & fs = m_isolate_factors;
|
factors & fs = m_isolate_factors;
|
||||||
|
@ -586,6 +586,7 @@ namespace algebraic_numbers {
|
||||||
upolynomial::numeral_vector const & f = fs[i];
|
upolynomial::numeral_vector const & f = fs[i];
|
||||||
// polynomial f contains the non zero roots
|
// polynomial f contains the non zero roots
|
||||||
unsigned d = upm().degree(f);
|
unsigned d = upm().degree(f);
|
||||||
|
TRACE("algebraic", tout << "factor " << i << " degree: " << d << "\n";);
|
||||||
if (d == 0)
|
if (d == 0)
|
||||||
continue; // found all roots of f
|
continue; // found all roots of f
|
||||||
scoped_mpq r(qm());
|
scoped_mpq r(qm());
|
||||||
|
@ -603,6 +604,7 @@ namespace algebraic_numbers {
|
||||||
upm().sqf_isolate_roots(f.size(), f.c_ptr(), bqm(), m_isolate_roots, m_isolate_lowers, m_isolate_uppers);
|
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();
|
unsigned sz = m_isolate_roots.size();
|
||||||
|
TRACE("algebraic", tout << "isolated roots: " << sz << "\n";);
|
||||||
for (unsigned i = 0; i < sz; i++) {
|
for (unsigned i = 0; i < sz; i++) {
|
||||||
to_mpq(qm(), m_isolate_roots[i], r);
|
to_mpq(qm(), m_isolate_roots[i], r);
|
||||||
roots.push_back(numeral(mk_basic_cell(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'),
|
('v1', BOOL, False, 'use Z3 version 1.x pretty printer'),
|
||||||
('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) 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)'),
|
('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_args(m),
|
||||||
m_hnf(m),
|
m_hnf(m),
|
||||||
m_qe(m),
|
m_qe(m),
|
||||||
m_cfg(m),
|
m_rwr(m),
|
||||||
m_rwr(m, false, m_cfg),
|
|
||||||
m_ufproc(m) {}
|
m_ufproc(m) {}
|
||||||
|
|
||||||
void rule_manager::inc_ref(rule * r) {
|
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) {
|
void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) {
|
||||||
expr_ref tmp(m);
|
m_rwr.remove_labels(fml, pr);
|
||||||
m_rwr(fml, tmp);
|
|
||||||
if (pr && fml != tmp) {
|
|
||||||
|
|
||||||
pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp));
|
|
||||||
}
|
|
||||||
fml = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var_idx_set& rule_manager::collect_vars(expr* e) {
|
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"qe_lite.h"
|
||||||
#include"var_subst.h"
|
#include"var_subst.h"
|
||||||
#include"datatype_decl_plugin.h"
|
#include"datatype_decl_plugin.h"
|
||||||
|
#include"label_rewriter.h"
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
|
||||||
|
@ -102,16 +103,6 @@ namespace datalog {
|
||||||
*/
|
*/
|
||||||
class rule_manager
|
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;
|
ast_manager& m;
|
||||||
context& m_ctx;
|
context& m_ctx;
|
||||||
rule_counter m_counter;
|
rule_counter m_counter;
|
||||||
|
@ -124,8 +115,7 @@ namespace datalog {
|
||||||
svector<bool> m_neg;
|
svector<bool> m_neg;
|
||||||
hnf m_hnf;
|
hnf m_hnf;
|
||||||
qe_lite m_qe;
|
qe_lite m_qe;
|
||||||
remove_label_cfg m_cfg;
|
label_rewriter m_rwr;
|
||||||
rewriter_tpl<remove_label_cfg> m_rwr;
|
|
||||||
mutable uninterpreted_function_finder_proc m_ufproc;
|
mutable uninterpreted_function_finder_proc m_ufproc;
|
||||||
mutable quantifier_finder_proc m_qproc;
|
mutable quantifier_finder_proc m_qproc;
|
||||||
mutable expr_sparse_mark m_visited;
|
mutable expr_sparse_mark m_visited;
|
||||||
|
|
|
@ -29,7 +29,6 @@ Revision History:
|
||||||
#include"ast_counter.h"
|
#include"ast_counter.h"
|
||||||
#include"statistics.h"
|
#include"statistics.h"
|
||||||
#include"lbool.h"
|
#include"lbool.h"
|
||||||
#include"qe_util.h"
|
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
||||||
#include "pdr_closure.h"
|
#include "pdr_closure.h"
|
||||||
#include "pdr_context.h"
|
#include "pdr_context.h"
|
||||||
#include "expr_safe_replace.h"
|
#include "expr_safe_replace.h"
|
||||||
|
#include "ast_util.h"
|
||||||
|
|
||||||
namespace pdr {
|
namespace pdr {
|
||||||
|
|
||||||
|
@ -147,7 +148,7 @@ namespace pdr {
|
||||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||||
fmls[i] = close_fml(fmls[i].get());
|
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) {
|
expr_ref closure::relax(unsigned i, expr* fml) {
|
||||||
|
@ -169,7 +170,7 @@ namespace pdr {
|
||||||
for (unsigned i = 0; i < As.size(); ++i) {
|
for (unsigned i = 0; i < As.size(); ++i) {
|
||||||
fmls.push_back(relax(i, As[i]));
|
fmls.push_back(relax(i, As[i]));
|
||||||
}
|
}
|
||||||
B = qe::mk_and(fmls);
|
B = mk_and(fmls);
|
||||||
return B;
|
return B;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,6 @@ Notes:
|
||||||
#include "smt_value_sort.h"
|
#include "smt_value_sort.h"
|
||||||
#include "proof_utils.h"
|
#include "proof_utils.h"
|
||||||
#include "dl_boogie_proof.h"
|
#include "dl_boogie_proof.h"
|
||||||
#include "qe_util.h"
|
|
||||||
#include "scoped_proof.h"
|
#include "scoped_proof.h"
|
||||||
#include "blast_term_ite_tactic.h"
|
#include "blast_term_ite_tactic.h"
|
||||||
#include "model_implicant.h"
|
#include "model_implicant.h"
|
||||||
|
|
|
@ -201,7 +201,7 @@ namespace pdr {
|
||||||
lits.push_back(extract_consequence(lo, hi));
|
lits.push_back(extract_consequence(lo, hi));
|
||||||
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"; } });
|
IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } });
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -415,6 +415,7 @@ namespace pdr {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class collect_pure_proc {
|
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) {
|
void core_farkas_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) {
|
||||||
ast_manager& m = n.pt().get_manager();
|
ast_manager& m = n.pt().get_manager();
|
||||||
if (core.empty()) return;
|
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);
|
expr_ref_vector Bs(m);
|
||||||
flatten_or(B, Bs);
|
flatten_or(B, Bs);
|
||||||
A = n.pt().get_propagation_formula(m_ctx.get_pred_transformers(), n.level());
|
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)) {
|
if (m_farkas_learner.get_lemma_guesses(A, B, lemmas)) {
|
||||||
TRACE("pdr",
|
TRACE("pdr",
|
||||||
tout << "Old core:\n" << mk_pp(B, m) << "\n";
|
tout << "Old core:\n" << mk_pp(B, m) << "\n";
|
||||||
tout << "New core:\n" << mk_pp(qe::mk_and(lemmas), m) << "\n";);
|
tout << "New core:\n" << mk_and(lemmas) << "\n";);
|
||||||
Bs[i] = qe::mk_and(lemmas);
|
Bs[i] = mk_and(lemmas);
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (change) {
|
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";);
|
TRACE("pdr", tout << "prop:\n" << mk_pp(A,m) << "\ngen:" << mk_pp(B, m) << "\nto: " << mk_pp(C, m) << "\n";);
|
||||||
core.reset();
|
core.reset();
|
||||||
flatten_and(C, core);
|
flatten_and(C, core);
|
||||||
|
@ -186,7 +186,7 @@ namespace pdr {
|
||||||
}
|
}
|
||||||
closure cl(n.pt(), m_is_closure);
|
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);
|
expr_ref fml2 = n.pt().get_formulas(n.level(), false);
|
||||||
fml1_2.push_back(fml1);
|
fml1_2.push_back(fml1);
|
||||||
fml1_2.push_back(0);
|
fml1_2.push_back(0);
|
||||||
|
@ -205,7 +205,7 @@ namespace pdr {
|
||||||
if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) {
|
if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) {
|
||||||
new_cores.push_back(std::make_pair(conv2, uses_level1));
|
new_cores.push_back(std::make_pair(conv2, uses_level1));
|
||||||
change = true;
|
change = true;
|
||||||
expr_ref state1 = qe::mk_and(conv2);
|
expr_ref state1 = mk_and(conv2);
|
||||||
TRACE("pdr",
|
TRACE("pdr",
|
||||||
tout << mk_pp(state, m) << "\n";
|
tout << mk_pp(state, m) << "\n";
|
||||||
tout << "Generalized to:\n" << mk_pp(state1, 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++) {
|
for (unsigned i = ut_size; i < t_size; i++) {
|
||||||
conj.push_back(rule.get_tail(i));
|
conj.push_back(rule.get_tail(i));
|
||||||
}
|
}
|
||||||
result = qe::mk_and(conj);
|
result = mk_and(conj);
|
||||||
if (!sub.empty()) {
|
if (!sub.empty()) {
|
||||||
expr_ref tmp = result;
|
expr_ref tmp = result;
|
||||||
var_subst(m, false)(tmp, sub.size(), sub.c_ptr(), 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) {
|
for (unsigned i = 0; i < rules.size(); ++i) {
|
||||||
fmls.push_back(m.mk_not(mk_transition_rule(reps, level, *rules[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";);
|
TRACE("pdr", tout << mk_pp(fml, m) << "\n";);
|
||||||
return fml;
|
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";);
|
TRACE("pdr", tout << mk_pp(result, m) << "\n";);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ Copyright (c) 2015 Microsoft Corporation
|
||||||
|
|
||||||
#include "check_relation.h"
|
#include "check_relation.h"
|
||||||
#include "dl_relation_manager.h"
|
#include "dl_relation_manager.h"
|
||||||
#include "qe_util.h"
|
|
||||||
#include "ast_util.h"
|
#include "ast_util.h"
|
||||||
#include "smt_kernel.h"
|
#include "smt_kernel.h"
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
|
@ -23,7 +23,6 @@ Notes:
|
||||||
--*/
|
--*/
|
||||||
#include "udoc_relation.h"
|
#include "udoc_relation.h"
|
||||||
#include "dl_relation_manager.h"
|
#include "dl_relation_manager.h"
|
||||||
#include "qe_util.h"
|
|
||||||
#include "ast_util.h"
|
#include "ast_util.h"
|
||||||
#include "smt_kernel.h"
|
#include "smt_kernel.h"
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,17 @@ namespace nlsat {
|
||||||
m_values.swap(other.m_values);
|
m_values.swap(other.m_values);
|
||||||
m_assigned.swap(other.m_assigned);
|
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) {
|
void set_core(var x, anum & v) {
|
||||||
m_values.reserve(x+1, anum());
|
m_values.reserve(x+1, anum());
|
||||||
m_assigned.reserve(x+1, false);
|
m_assigned.reserve(x+1, false);
|
||||||
|
@ -52,11 +63,26 @@ namespace nlsat {
|
||||||
am().set(m_values[x], v);
|
am().set(m_values[x], v);
|
||||||
}
|
}
|
||||||
void reset(var x) { if (x < m_assigned.size()) m_assigned[x] = false; }
|
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); }
|
bool is_assigned(var x) const { return m_assigned.get(x, false); }
|
||||||
anum const & value(var x) const { return m_values[x]; }
|
anum const & value(var x) const { return m_values[x]; }
|
||||||
virtual anum_manager & m() const { return am(); }
|
virtual anum_manager & m() const { return am(); }
|
||||||
virtual bool contains(var x) const { return is_assigned(x); }
|
virtual bool contains(var x) const { return is_assigned(x); }
|
||||||
virtual anum const & operator()(var x) const { SASSERT(is_assigned(x)); return value(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_evaluator.h"
|
||||||
|
#include"nlsat_solver.h"
|
||||||
|
|
||||||
namespace nlsat {
|
namespace nlsat {
|
||||||
|
|
||||||
struct evaluator::imp {
|
struct evaluator::imp {
|
||||||
|
solver& m_solver;
|
||||||
assignment const & m_assignment;
|
assignment const & m_assignment;
|
||||||
pmanager & m_pm;
|
pmanager & m_pm;
|
||||||
small_object_allocator & m_allocator;
|
small_object_allocator & m_allocator;
|
||||||
|
@ -357,7 +359,8 @@ namespace nlsat {
|
||||||
|
|
||||||
sign_table m_sign_table_tmp;
|
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_assignment(x2v),
|
||||||
m_pm(pm),
|
m_pm(pm),
|
||||||
m_allocator(allocator),
|
m_allocator(allocator),
|
||||||
|
@ -420,9 +423,24 @@ namespace nlsat {
|
||||||
scoped_anum_vector & roots = m_tmp_values;
|
scoped_anum_vector & roots = m_tmp_values;
|
||||||
roots.reset();
|
roots.reset();
|
||||||
m_am.isolate_roots(polynomial_ref(a->p(), m_pm), undef_var_assignment(m_assignment, a->x()), roots);
|
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);
|
SASSERT(a->i() > 0);
|
||||||
if (a->i() > roots.size())
|
if (a->i() > roots.size()) {
|
||||||
return false; // p does have sufficient roots
|
return neg;
|
||||||
|
}
|
||||||
int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]);
|
int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]);
|
||||||
return satisfied(sign, k, neg);
|
return satisfied(sign, k, neg);
|
||||||
}
|
}
|
||||||
|
@ -649,8 +667,8 @@ namespace nlsat {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
evaluator::evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator) {
|
evaluator::evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator) {
|
||||||
m_imp = alloc(imp, x2v, pm, allocator);
|
m_imp = alloc(imp, s, x2v, pm, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluator::~evaluator() {
|
evaluator::~evaluator() {
|
||||||
|
|
|
@ -26,11 +26,13 @@ Revision History:
|
||||||
|
|
||||||
namespace nlsat {
|
namespace nlsat {
|
||||||
|
|
||||||
|
class solver;
|
||||||
|
|
||||||
class evaluator {
|
class evaluator {
|
||||||
struct imp;
|
struct imp;
|
||||||
imp * m_imp;
|
imp * m_imp;
|
||||||
public:
|
public:
|
||||||
evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator);
|
evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator);
|
||||||
~evaluator();
|
~evaluator();
|
||||||
|
|
||||||
interval_set_manager & ism() const;
|
interval_set_manager & ism() const;
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace nlsat {
|
||||||
polynomial::cache & m_cache;
|
polynomial::cache & m_cache;
|
||||||
pmanager & m_pm;
|
pmanager & m_pm;
|
||||||
polynomial_ref_vector m_ps;
|
polynomial_ref_vector m_ps;
|
||||||
|
polynomial_ref_vector m_ps2;
|
||||||
polynomial_ref_vector m_psc_tmp;
|
polynomial_ref_vector m_psc_tmp;
|
||||||
polynomial_ref_vector m_factors;
|
polynomial_ref_vector m_factors;
|
||||||
scoped_anum_vector m_roots_tmp;
|
scoped_anum_vector m_roots_tmp;
|
||||||
|
@ -43,6 +44,7 @@ namespace nlsat {
|
||||||
bool m_full_dimensional;
|
bool m_full_dimensional;
|
||||||
bool m_minimize_cores;
|
bool m_minimize_cores;
|
||||||
bool m_factor;
|
bool m_factor;
|
||||||
|
bool m_signed_project;
|
||||||
|
|
||||||
struct todo_set {
|
struct todo_set {
|
||||||
polynomial::cache & m_cache;
|
polynomial::cache & m_cache;
|
||||||
|
@ -137,6 +139,7 @@ namespace nlsat {
|
||||||
m_cache(u),
|
m_cache(u),
|
||||||
m_pm(u.pm()),
|
m_pm(u.pm()),
|
||||||
m_ps(m_pm),
|
m_ps(m_pm),
|
||||||
|
m_ps2(m_pm),
|
||||||
m_psc_tmp(m_pm),
|
m_psc_tmp(m_pm),
|
||||||
m_factors(m_pm),
|
m_factors(m_pm),
|
||||||
m_roots_tmp(m_am),
|
m_roots_tmp(m_am),
|
||||||
|
@ -148,6 +151,7 @@ namespace nlsat {
|
||||||
m_simplify_cores = false;
|
m_simplify_cores = false;
|
||||||
m_full_dimensional = false;
|
m_full_dimensional = false;
|
||||||
m_minimize_cores = false;
|
m_minimize_cores = false;
|
||||||
|
m_signed_project = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
~imp() {
|
~imp() {
|
||||||
|
@ -212,7 +216,7 @@ namespace nlsat {
|
||||||
max_var(p) must be assigned in the current interpretation.
|
max_var(p) must be assigned in the current interpretation.
|
||||||
*/
|
*/
|
||||||
int sign(polynomial_ref const & p) {
|
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)));
|
SASSERT(max_var(p) == null_var || m_assignment.is_assigned(max_var(p)));
|
||||||
return m_am.eval_sign_at(p, m_assignment);
|
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) {
|
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());
|
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)) {
|
if (m_pm.degree(p, y) == 1 && m_pm.const_coeff(p, y, 1, c)) {
|
||||||
SASSERT(!m_pm.m().is_zero(c));
|
SASSERT(!m_pm.m().is_zero(c));
|
||||||
// literal can be expressed using a linear ineq_atom
|
mk_linear_root(k, y, i, p, m_pm.m().is_neg(c));
|
||||||
polynomial_ref p_prime(m_pm);
|
return true;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else {
|
return false;
|
||||||
b = m_solver.mk_root_atom(k, y, i, p);
|
}
|
||||||
lsign = 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
|
polynomial_ref c(m_pm);
|
||||||
literal l(b, lsign);
|
c = m_pm.coeff(p, y, 1);
|
||||||
TRACE("nlsat_explain", tout << "adding literal\n"; display(tout, l); tout << "\n";);
|
int s = sign(c);
|
||||||
add_literal(l);
|
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););
|
TRACE("nlsat_explain", tout << "[explain] result\n"; display(tout, result););
|
||||||
CASSERT("nlsat", check_already_added());
|
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,
|
explain::explain(solver & s, assignment const & x2v, polynomial::cache & u,
|
||||||
evaluator & ev) {
|
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev) {
|
||||||
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev);
|
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1364,10 +1815,26 @@ namespace nlsat {
|
||||||
m_imp->m_factor = f;
|
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) {
|
void explain::operator()(unsigned n, literal const * ls, scoped_literal_vector & result) {
|
||||||
(*m_imp)(n, ls, 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
|
#ifdef Z3DEBUG
|
||||||
|
@ -1398,3 +1865,4 @@ void pp_lit(nlsat::explain::imp & ex, nlsat::literal l) {
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,20 @@ Revision History:
|
||||||
#include"nlsat_solver.h"
|
#include"nlsat_solver.h"
|
||||||
#include"nlsat_scoped_literal_vector.h"
|
#include"nlsat_scoped_literal_vector.h"
|
||||||
#include"polynomial_cache.h"
|
#include"polynomial_cache.h"
|
||||||
|
#include"algebraic_numbers.h"
|
||||||
|
|
||||||
namespace nlsat {
|
namespace nlsat {
|
||||||
class evaluator;
|
class evaluator;
|
||||||
|
|
||||||
|
|
||||||
class explain {
|
class explain {
|
||||||
public:
|
public:
|
||||||
struct imp;
|
struct imp;
|
||||||
private:
|
private:
|
||||||
imp * m_imp;
|
imp * m_imp;
|
||||||
public:
|
public:
|
||||||
explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq,
|
explain(solver & s, assignment const & x2v, polynomial::cache & u,
|
||||||
evaluator & ev);
|
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev);
|
||||||
~explain();
|
~explain();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -41,6 +43,7 @@ namespace nlsat {
|
||||||
void set_full_dimensional(bool f);
|
void set_full_dimensional(bool f);
|
||||||
void set_minimize_cores(bool f);
|
void set_minimize_cores(bool f);
|
||||||
void set_factor(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.
|
\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
|
- s_1, ..., s_m are false in the current interpretation
|
||||||
*/
|
*/
|
||||||
void operator()(unsigned n, literal const * ls, scoped_literal_vector & result);
|
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++)
|
for (unsigned i = 0; i < sz; i++)
|
||||||
push_back(ls[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 polynomial::cache cache;
|
||||||
typedef ptr_vector<interval_set> interval_set_vector;
|
typedef ptr_vector<interval_set> interval_set_vector;
|
||||||
|
|
||||||
solver & m_solver;
|
|
||||||
reslimit& m_rlimit;
|
reslimit& m_rlimit;
|
||||||
small_object_allocator m_allocator;
|
small_object_allocator m_allocator;
|
||||||
unsynch_mpq_manager m_qm;
|
unsynch_mpq_manager m_qm;
|
||||||
|
@ -159,8 +158,7 @@ namespace nlsat {
|
||||||
unsigned m_stages;
|
unsigned m_stages;
|
||||||
unsigned m_irrational_assignments; // number of irrational witnesses
|
unsigned m_irrational_assignments; // number of irrational witnesses
|
||||||
|
|
||||||
imp(solver & s, reslimit& rlim, params_ref const & p):
|
imp(solver& s, reslimit& rlim, params_ref const & p):
|
||||||
m_solver(s),
|
|
||||||
m_rlimit(rlim),
|
m_rlimit(rlim),
|
||||||
m_allocator("nlsat"),
|
m_allocator("nlsat"),
|
||||||
m_pm(rlim, m_qm, &m_allocator),
|
m_pm(rlim, m_qm, &m_allocator),
|
||||||
|
@ -168,7 +166,7 @@ namespace nlsat {
|
||||||
m_am(rlim, m_qm, p, &m_allocator),
|
m_am(rlim, m_qm, p, &m_allocator),
|
||||||
m_asm(*this, m_allocator),
|
m_asm(*this, m_allocator),
|
||||||
m_assignment(m_am),
|
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_ism(m_evaluator.ism()),
|
||||||
m_num_bool_vars(0),
|
m_num_bool_vars(0),
|
||||||
m_display_var(m_perm),
|
m_display_var(m_perm),
|
||||||
|
@ -183,12 +181,7 @@ namespace nlsat {
|
||||||
}
|
}
|
||||||
|
|
||||||
~imp() {
|
~imp() {
|
||||||
m_explain.reset();
|
reset();
|
||||||
m_lemma.reset();
|
|
||||||
m_lazy_clause.reset();
|
|
||||||
undo_until_size(0);
|
|
||||||
del_clauses();
|
|
||||||
del_unref_atoms();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mk_true_bvar() {
|
void mk_true_bvar() {
|
||||||
|
@ -216,6 +209,18 @@ namespace nlsat {
|
||||||
m_am.updt_params(p.p);
|
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() {
|
void checkpoint() {
|
||||||
if (!m_rlimit.inc()) throw solver_exception(m_rlimit.get_cancel_msg());
|
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);
|
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) {
|
void inc_ref(bool_var b) {
|
||||||
|
TRACE("ref", tout << "inc: " << b << "\n";);
|
||||||
if (b == null_bool_var)
|
if (b == null_bool_var)
|
||||||
return;
|
return;
|
||||||
if (m_atoms[b] == 0)
|
if (m_atoms[b] == 0)
|
||||||
|
@ -264,6 +270,7 @@ namespace nlsat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void dec_ref(bool_var b) {
|
void dec_ref(bool_var b) {
|
||||||
|
TRACE("ref", tout << "dec: " << b << "\n";);
|
||||||
if (b == null_bool_var)
|
if (b == null_bool_var)
|
||||||
return;
|
return;
|
||||||
atom * a = m_atoms[b];
|
atom * a = m_atoms[b];
|
||||||
|
@ -412,6 +419,34 @@ namespace nlsat {
|
||||||
return x;
|
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) {
|
void deallocate(ineq_atom * a) {
|
||||||
unsigned obj_sz = ineq_atom::get_obj_size(a->size());
|
unsigned obj_sz = ineq_atom::get_obj_size(a->size());
|
||||||
a->~ineq_atom();
|
a->~ineq_atom();
|
||||||
|
@ -491,6 +526,7 @@ namespace nlsat {
|
||||||
TRACE("nlsat_table_bug", ineq_atom::hash_proc h;
|
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";);
|
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);
|
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);
|
SASSERT(old_atom->max_var() == max);
|
||||||
if (old_atom != new_atom) {
|
if (old_atom != new_atom) {
|
||||||
deallocate(new_atom);
|
deallocate(new_atom);
|
||||||
|
@ -726,7 +762,7 @@ namespace nlsat {
|
||||||
|
|
||||||
template<typename Predicate>
|
template<typename Predicate>
|
||||||
void undo_until(Predicate const & pred) {
|
void undo_until(Predicate const & pred) {
|
||||||
while (pred()) {
|
while (pred() && !m_trail.empty()) {
|
||||||
trail & t = m_trail.back();
|
trail & t = m_trail.back();
|
||||||
switch (t.m_kind) {
|
switch (t.m_kind) {
|
||||||
case trail::BVAR_ASSIGNMENT:
|
case trail::BVAR_ASSIGNMENT:
|
||||||
|
@ -803,6 +839,14 @@ namespace nlsat {
|
||||||
SASSERT(m_bvalues[b] == l_undef);
|
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
|
\brief Create a new scope level
|
||||||
*/
|
*/
|
||||||
|
@ -868,10 +912,11 @@ namespace nlsat {
|
||||||
var max = a->max_var();
|
var max = a->max_var();
|
||||||
if (!m_assignment.is_assigned(max))
|
if (!m_assignment.is_assigned(max))
|
||||||
return l_undef;
|
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";
|
val = to_lbool(m_evaluator.eval(a, l.sign()));
|
||||||
display_assignment(tout);
|
TRACE("value_bug", tout << "value of: "; display(tout, l); tout << " := " << val << "\n";
|
||||||
display_bool_assignment(tout););
|
tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n";
|
||||||
return to_lbool(m_evaluator.eval(a, l.sign()));
|
display_assignment(tout););
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -880,8 +925,10 @@ namespace nlsat {
|
||||||
bool is_satisfied(clause const & cls) const {
|
bool is_satisfied(clause const & cls) const {
|
||||||
unsigned sz = cls.size();
|
unsigned sz = cls.size();
|
||||||
for (unsigned i = 0; i < sz; i++) {
|
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 true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -984,8 +1031,10 @@ namespace nlsat {
|
||||||
If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0
|
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) {
|
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
|
return true; // ignore lemmas in super lazy mode
|
||||||
|
}
|
||||||
SASSERT(m_xk == max_var(cls));
|
SASSERT(m_xk == max_var(cls));
|
||||||
unsigned num_undef = 0; // number of undefined literals
|
unsigned num_undef = 0; // number of undefined literals
|
||||||
unsigned first_undef = UINT_MAX; // position of the first undefined literal
|
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
|
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) {
|
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))
|
if (is_satisfied(cls))
|
||||||
return true;
|
return true;
|
||||||
if (m_xk == null_var)
|
if (m_xk == null_var)
|
||||||
|
@ -1151,7 +1200,7 @@ namespace nlsat {
|
||||||
}
|
}
|
||||||
TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";);
|
TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";);
|
||||||
if (m_bk == null_bool_var && m_xk >= num_vars()) {
|
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.
|
return l_true; // all variables were assigned, and all clauses were satisfied.
|
||||||
}
|
}
|
||||||
TRACE("nlsat", tout << "processing variable ";
|
TRACE("nlsat", tout << "processing variable ";
|
||||||
|
@ -1186,23 +1235,102 @@ namespace nlsat {
|
||||||
lbool check() {
|
lbool check() {
|
||||||
TRACE("nlsat_smt2", display_smt2(tout););
|
TRACE("nlsat_smt2", display_smt2(tout););
|
||||||
TRACE("nlsat_fd", tout << "is_full_dimensional: " << is_full_dimensional() << "\n";);
|
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());
|
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();
|
shuffle_vars();
|
||||||
|
reordered = true;
|
||||||
}
|
}
|
||||||
else if (m_reorder) {
|
else if (m_reorder) {
|
||||||
heuristic_reorder();
|
heuristic_reorder();
|
||||||
|
reordered = true;
|
||||||
}
|
}
|
||||||
sort_watched_clauses();
|
sort_watched_clauses();
|
||||||
lbool r = search();
|
lbool r = search();
|
||||||
CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout); display_bool_assignment(tout););
|
CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout););
|
||||||
if (m_reorder)
|
if (reordered)
|
||||||
restore_order();
|
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;
|
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
|
// Conflict Resolution
|
||||||
|
@ -1447,7 +1575,7 @@ namespace nlsat {
|
||||||
TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n";
|
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 << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << "<null>"; tout << "\n";
|
||||||
tout << "scope_lvl: " << scope_lvl() << "\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;
|
// static unsigned counter = 0;
|
||||||
// counter++;
|
// counter++;
|
||||||
|
@ -1588,7 +1716,7 @@ namespace nlsat {
|
||||||
conflict_clause = new_cls;
|
conflict_clause = new_cls;
|
||||||
goto start;
|
goto start;
|
||||||
}
|
}
|
||||||
TRACE("nlsat_resolve_done", display_assignment(tout); display_bool_assignment(tout););
|
TRACE("nlsat_resolve_done", display_assignment(tout););
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1801,6 +1929,15 @@ namespace nlsat {
|
||||||
reorder(p.size(), p.c_ptr());
|
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.
|
\brief Reorder variables using the giving permutation.
|
||||||
p maps internal variables to their new positions
|
p maps internal variables to their new positions
|
||||||
|
@ -1921,6 +2058,9 @@ namespace nlsat {
|
||||||
void reinit_cache() {
|
void reinit_cache() {
|
||||||
reinit_cache(m_clauses);
|
reinit_cache(m_clauses);
|
||||||
reinit_cache(m_learned);
|
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) {
|
void reinit_cache(clause_vector const & cs) {
|
||||||
unsigned sz = cs.size();
|
unsigned sz = cs.size();
|
||||||
|
@ -1934,10 +2074,13 @@ namespace nlsat {
|
||||||
}
|
}
|
||||||
void reinit_cache(literal l) {
|
void reinit_cache(literal l) {
|
||||||
bool_var b = l.var();
|
bool_var b = l.var();
|
||||||
atom * a = m_atoms[b];
|
reinit_cache(m_atoms[b]);
|
||||||
if (a == 0)
|
}
|
||||||
return;
|
void reinit_cache(atom* a) {
|
||||||
if (a->is_ineq_atom()) {
|
if (a == 0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (a->is_ineq_atom()) {
|
||||||
var max = 0;
|
var max = 0;
|
||||||
unsigned sz = to_ineq_atom(a)->size();
|
unsigned sz = to_ineq_atom(a)->size();
|
||||||
for (unsigned i = 0; i < sz; i++) {
|
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++) {
|
for (var x = 0; x < num_vars(); x++) {
|
||||||
if (m_assignment.is_assigned(x)) {
|
if (m_assignment.is_assigned(x)) {
|
||||||
proc(out, 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();
|
unsigned sz = m_atoms.size();
|
||||||
for (bool_var b = 0; b < sz; b++) {
|
for (bool_var b = 0; b < sz; b++) {
|
||||||
if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) {
|
if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) {
|
||||||
|
@ -2112,12 +2255,13 @@ namespace nlsat {
|
||||||
return !first;
|
return !first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_assignment(std::ostream & out) const {
|
void display_num_assignment(std::ostream & out) const {
|
||||||
display_assignment(out, m_display_var);
|
display_num_assignment(out, m_display_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_bool_assignment(std::ostream & out) const {
|
void display_assignment(std::ostream& out) const {
|
||||||
display_bool_assignment(out, m_display_var);
|
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 {
|
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 {
|
void display(std::ostream & out) const {
|
||||||
display(out, m_display_var);
|
display(out, m_display_var);
|
||||||
|
display_assignment(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_vars(std::ostream & out) const {
|
void display_vars(std::ostream & out) const {
|
||||||
|
@ -2562,6 +2707,20 @@ namespace nlsat {
|
||||||
return m_imp->check();
|
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) {
|
void solver::collect_param_descrs(param_descrs & d) {
|
||||||
algebraic_numbers::manager::collect_param_descrs(d);
|
algebraic_numbers::manager::collect_param_descrs(d);
|
||||||
nlsat_params::collect_param_descrs(d);
|
nlsat_params::collect_param_descrs(d);
|
||||||
|
@ -2583,6 +2742,10 @@ namespace nlsat {
|
||||||
m_imp->m_display_var.m_proc = &proc;
|
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 {
|
bool solver::is_int(var x) const {
|
||||||
return m_imp->is_int(x);
|
return m_imp->is_int(x);
|
||||||
}
|
}
|
||||||
|
@ -2591,10 +2754,61 @@ namespace nlsat {
|
||||||
return m_imp->mk_bool_var();
|
return m_imp->mk_bool_var();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
literal solver::mk_true() {
|
||||||
|
return literal(0, false);
|
||||||
|
}
|
||||||
|
|
||||||
atom * solver::bool_var2atom(bool_var b) {
|
atom * solver::bool_var2atom(bool_var b) {
|
||||||
return m_imp->m_atoms[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) {
|
var solver::mk_var(bool is_int) {
|
||||||
return m_imp->mk_var(is_int);
|
return m_imp->mk_var(is_int);
|
||||||
}
|
}
|
||||||
|
@ -2631,10 +2845,21 @@ namespace nlsat {
|
||||||
m_imp->display(out, l);
|
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 {
|
void solver::display(std::ostream & out, var x) const {
|
||||||
m_imp->m_display_var(out, x);
|
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 {
|
display_var_proc const & solver::display_proc() const {
|
||||||
return m_imp->m_display_var;
|
return m_imp->m_display_var;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ Revision History:
|
||||||
|
|
||||||
namespace nlsat {
|
namespace nlsat {
|
||||||
|
|
||||||
|
class evaluator;
|
||||||
|
class explain;
|
||||||
|
|
||||||
class solver {
|
class solver {
|
||||||
struct imp;
|
struct imp;
|
||||||
imp * m_imp;
|
imp * m_imp;
|
||||||
|
@ -64,6 +67,8 @@ namespace nlsat {
|
||||||
*/
|
*/
|
||||||
bool_var mk_bool_var();
|
bool_var mk_bool_var();
|
||||||
|
|
||||||
|
literal mk_true();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Create a real/integer variable.
|
\brief Create a real/integer variable.
|
||||||
*/
|
*/
|
||||||
|
@ -121,6 +126,48 @@ namespace nlsat {
|
||||||
*/
|
*/
|
||||||
atom * bool_var2atom(bool_var b);
|
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
|
\brief Return number of integer/real variables
|
||||||
*/
|
*/
|
||||||
|
@ -135,6 +182,8 @@ namespace nlsat {
|
||||||
// -----------------------
|
// -----------------------
|
||||||
lbool check();
|
lbool check();
|
||||||
|
|
||||||
|
lbool check(literal_vector& assumptions);
|
||||||
|
|
||||||
// -----------------------
|
// -----------------------
|
||||||
//
|
//
|
||||||
// Model
|
// Model
|
||||||
|
@ -154,6 +203,7 @@ namespace nlsat {
|
||||||
void updt_params(params_ref const & p);
|
void updt_params(params_ref const & p);
|
||||||
static void collect_param_descrs(param_descrs & d);
|
static void collect_param_descrs(param_descrs & d);
|
||||||
|
|
||||||
|
void reset();
|
||||||
void collect_statistics(statistics & st);
|
void collect_statistics(statistics & st);
|
||||||
void reset_statistics();
|
void reset_statistics();
|
||||||
void display_status(std::ostream & out) const;
|
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, 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
|
\brief Display variable
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -111,6 +111,21 @@ namespace nlsat {
|
||||||
struct eq_proc { bool operator()(ineq_atom const * a1, ineq_atom const * a2) const; };
|
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 {
|
class root_atom : public atom {
|
||||||
friend class solver;
|
friend class solver;
|
||||||
var m_x;
|
var m_x;
|
||||||
|
|
|
@ -29,7 +29,9 @@ Notes:
|
||||||
#include"expr2var.h"
|
#include"expr2var.h"
|
||||||
#include"arith_decl_plugin.h"
|
#include"arith_decl_plugin.h"
|
||||||
#include"tactic.h"
|
#include"tactic.h"
|
||||||
#include"ast_smt2_pp.h"
|
#include"ast_pp.h"
|
||||||
|
#include"polynomial.h"
|
||||||
|
#include"algebraic_numbers.h"
|
||||||
|
|
||||||
struct goal2nlsat::imp {
|
struct goal2nlsat::imp {
|
||||||
struct nlsat_expr2polynomial : public expr2polynomial {
|
struct nlsat_expr2polynomial : public expr2polynomial {
|
||||||
|
@ -124,7 +126,7 @@ struct goal2nlsat::imp {
|
||||||
m_qm.neg(d2);
|
m_qm.neg(d2);
|
||||||
polynomial_ref p(m_pm);
|
polynomial_ref p(m_pm);
|
||||||
p = m_pm.addmul(d1, m_pm.mk_unit(), p1, d2, m_pm.mk_unit(), p2);
|
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)) {
|
if (is_const(p)) {
|
||||||
int sign;
|
int sign;
|
||||||
if (is_zero(p))
|
if (is_zero(p))
|
||||||
|
@ -192,7 +194,7 @@ struct goal2nlsat::imp {
|
||||||
switch (to_app(f)->get_decl_kind()) {
|
switch (to_app(f)->get_decl_kind()) {
|
||||||
case OP_TRUE:
|
case OP_TRUE:
|
||||||
case OP_FALSE:
|
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");
|
throw tactic_exception("apply simplify before applying nlsat");
|
||||||
case OP_AND:
|
case OP_AND:
|
||||||
case OP_OR:
|
case OP_OR:
|
||||||
|
@ -257,6 +259,7 @@ struct goal2nlsat::imp {
|
||||||
process(g.form(i), g.dep(i));
|
process(g.form(i), g.dep(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct goal2nlsat::scoped_set_imp {
|
struct goal2nlsat::scoped_set_imp {
|
||||||
|
@ -290,3 +293,153 @@ void goal2nlsat::operator()(goal const & g, params_ref const & p, nlsat::solver
|
||||||
local_imp(g);
|
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,16 +57,15 @@ class nlsat2goal {
|
||||||
struct imp;
|
struct imp;
|
||||||
imp * m_imp;
|
imp * m_imp;
|
||||||
public:
|
public:
|
||||||
nlsat2goal();
|
nlsat2goal(ast_manager& m);
|
||||||
~nlsat2goal();
|
~nlsat2goal();
|
||||||
|
|
||||||
static void collect_param_descrs(param_descrs & r);
|
static void collect_param_descrs(param_descrs & r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Translate the state of the nlsat engine back into a goal.
|
\brief Translate a literal into a formula.
|
||||||
*/
|
*/
|
||||||
void operator()(nlsat::solver const & s, expr2var const & a2b, expr2var const & t2x,
|
expr_ref operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l);
|
||||||
params_ref const & p, goal & g, model_converter_ref & mc);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -514,12 +514,10 @@ namespace opt {
|
||||||
|
|
||||||
void context::init_solver() {
|
void context::init_solver() {
|
||||||
setup_arith_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_opt_solver = alloc(opt_solver, m, m_params, m_fm);
|
m_solver = m_opt_solver.get();
|
||||||
m_opt_solver->set_logic(m_logic);
|
|
||||||
m_solver = m_opt_solver.get();
|
|
||||||
}
|
|
||||||
if (opt_params(m_params).priority() == symbol("pareto") ||
|
if (opt_params(m_params).priority() == symbol("pareto") ||
|
||||||
(opt_params(m_params).priority() == symbol("lex") && m_objectives.size() > 1)) {
|
(opt_params(m_params).priority() == symbol("lex") && m_objectives.size() > 1)) {
|
||||||
m_opt_solver->ensure_pb();
|
m_opt_solver->ensure_pb();
|
||||||
|
@ -556,10 +554,7 @@ namespace opt {
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
m_sat_solver->assert_expr(get_solver().get_assertion(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) {
|
void context::enable_sls(bool force) {
|
||||||
|
@ -649,10 +644,7 @@ namespace opt {
|
||||||
void context::add_maxsmt(symbol const& id, unsigned index) {
|
void context::add_maxsmt(symbol const& id, unsigned index) {
|
||||||
maxsmt* ms = alloc(maxsmt, *this, index);
|
maxsmt* ms = alloc(maxsmt, *this, index);
|
||||||
ms->updt_params(m_params);
|
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 {
|
bool context::is_numeral(expr* e, rational & n) const {
|
||||||
|
@ -1277,10 +1269,7 @@ namespace opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
void context::set_simplify(tactic* tac) {
|
void context::set_simplify(tactic* tac) {
|
||||||
#pragma omp critical (opt_context)
|
m_simplify = tac;
|
||||||
{
|
|
||||||
m_simplify = tac;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void context::clear_state() {
|
void context::clear_state() {
|
||||||
|
@ -1290,10 +1279,7 @@ namespace opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
void context::set_pareto(pareto_base* p) {
|
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 {
|
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 "expr_functors.h"
|
||||||
#include "quant_hoist.h"
|
#include "quant_hoist.h"
|
||||||
#include "bool_rewriter.h"
|
#include "bool_rewriter.h"
|
||||||
#include "qe_util.h"
|
|
||||||
#include "th_rewriter.h"
|
#include "th_rewriter.h"
|
||||||
#include "smt_kernel.h"
|
#include "smt_kernel.h"
|
||||||
#include "model_evaluator.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();
|
ast_manager& m = new_body.get_manager();
|
||||||
expr_ref tmp(m);
|
expr_ref tmp(m);
|
||||||
unsigned nd = q->get_num_decls();
|
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);
|
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 {
|
class def_vector {
|
||||||
func_decl_ref_vector m_vars;
|
func_decl_ref_vector m_vars;
|
||||||
expr_ref_vector m_defs;
|
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_
|
#define QE_ARITH_H_
|
||||||
|
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
#include "arith_decl_plugin.h"
|
||||||
|
#include "qe_mbp.h"
|
||||||
|
|
||||||
namespace qe {
|
namespace qe {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Loos-Weispfenning model-based projection for a basic conjunction.
|
Loos-Weispfenning model-based projection for a basic conjunction.
|
||||||
Lits is a vector of literals.
|
Lits is a vector of literals.
|
||||||
return vector of variables that could not be projected.
|
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
|
#endif
|
||||||
|
|
|
@ -32,6 +32,7 @@ Revision History:
|
||||||
#include "nlarith_util.h"
|
#include "nlarith_util.h"
|
||||||
#include "model_evaluator.h"
|
#include "model_evaluator.h"
|
||||||
#include "smt_kernel.h"
|
#include "smt_kernel.h"
|
||||||
|
#include "qe_arith.h"
|
||||||
|
|
||||||
namespace qe {
|
namespace qe {
|
||||||
|
|
||||||
|
@ -266,23 +267,8 @@ namespace qe {
|
||||||
//
|
//
|
||||||
// match 0 == p mod k, p mod k == 0
|
// match 0 == p mod k, p mod k == 0
|
||||||
//
|
//
|
||||||
bool is_divides(app* e, numeral& k, expr_ref& p) {
|
bool is_divides(expr* e, numeral& k, expr_ref& p) {
|
||||||
expr* e1, *e2;
|
return qe::is_divides(m_arith, e, k, p);
|
||||||
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_not_divides(app* e, app_ref& n, numeral& k, expr_ref& 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 "var_subst.h"
|
||||||
#include "uint_set.h"
|
#include "uint_set.h"
|
||||||
#include "ast_util.h"
|
#include "ast_util.h"
|
||||||
#include "qe_util.h"
|
|
||||||
#include "th_rewriter.h"
|
#include "th_rewriter.h"
|
||||||
#include "for_each_expr.h"
|
#include "for_each_expr.h"
|
||||||
#include "expr_safe_replace.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"
|
#include"qe.h"
|
||||||
|
|
||||||
class qe_tactic : public tactic {
|
class qe_tactic : public tactic {
|
||||||
|
statistics m_st;
|
||||||
struct imp {
|
struct imp {
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
smt_params m_fparams;
|
smt_params m_fparams;
|
||||||
|
@ -78,10 +79,19 @@ class qe_tactic : public tactic {
|
||||||
g->update(i, new_f, new_pr, g->dep(i));
|
g->update(i, new_f, new_pr, g->dep(i));
|
||||||
}
|
}
|
||||||
g->inc_depth();
|
g->inc_depth();
|
||||||
|
g->elim_true();
|
||||||
result.push_back(g.get());
|
result.push_back(g.get());
|
||||||
TRACE("qe", g->display(tout););
|
TRACE("qe", g->display(tout););
|
||||||
SASSERT(g->is_well_sorted());
|
SASSERT(g->is_well_sorted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void collect_statistics(statistics & st) const {
|
||||||
|
m_qe.collect_statistics(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_statistics() {
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
imp * m_imp;
|
imp * m_imp;
|
||||||
|
@ -117,8 +127,20 @@ public:
|
||||||
proof_converter_ref & pc,
|
proof_converter_ref & pc,
|
||||||
expr_dependency_ref & core) {
|
expr_dependency_ref & core) {
|
||||||
(*m_imp)(in, result, mc, pc, 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() {
|
virtual void cleanup() {
|
||||||
ast_manager & m = m_imp->m;
|
ast_manager & m = m_imp->m;
|
||||||
dealloc(m_imp);
|
dealloc(m_imp);
|
||||||
|
|
|
@ -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) {
|
if (m_preprocess) {
|
||||||
m_preprocess->reset();
|
m_preprocess->reset();
|
||||||
}
|
}
|
||||||
|
if (!m_bb_rewriter) {
|
||||||
|
m_bb_rewriter = alloc(bit_blaster_rewriter, m, m_params);
|
||||||
|
}
|
||||||
params_ref simp2_p = 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("som", true);
|
||||||
simp2_p.set_bool("pull_cheap_ite", true);
|
simp2_p.set_bool("pull_cheap_ite", true);
|
||||||
simp2_p.set_bool("push_ite_bv", false);
|
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.
|
// This information may be stored as a vector of pairs.
|
||||||
// The mapping is only created during the model conversion.
|
// The mapping is only created during the model conversion.
|
||||||
expr_ref_vector m_var2expr;
|
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):
|
sat_model_converter(ast_manager & m):
|
||||||
m_var2expr(m) {
|
m_var2expr(m) {
|
||||||
|
|
|
@ -66,7 +66,7 @@ void display_usage() {
|
||||||
#ifdef Z3GITHASH
|
#ifdef Z3GITHASH
|
||||||
std::cout << " - build hashcode " << STRINGIZE_VALUE_OF(Z3GITHASH);
|
std::cout << " - build hashcode " << STRINGIZE_VALUE_OF(Z3GITHASH);
|
||||||
#endif
|
#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 << "Usage: z3 [options] [-file:]file\n";
|
||||||
std::cout << "\nInput format:\n";
|
std::cout << "\nInput format:\n";
|
||||||
std::cout << " -smt use parser for SMT input 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(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);
|
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;
|
maximise_bv_sharing m_bv_sharing;
|
||||||
|
|
||||||
bool m_inconsistent;
|
bool m_inconsistent;
|
||||||
// qe::expr_quant_elim_star1 m_quant_elim;
|
|
||||||
|
|
||||||
struct scope {
|
struct scope {
|
||||||
unsigned m_asserted_formulas_lim;
|
unsigned m_asserted_formulas_lim;
|
||||||
|
@ -84,7 +83,6 @@ class asserted_formulas {
|
||||||
void eliminate_and();
|
void eliminate_and();
|
||||||
void refine_inj_axiom();
|
void refine_inj_axiom();
|
||||||
bool cheap_quant_fourier_motzkin();
|
bool cheap_quant_fourier_motzkin();
|
||||||
bool quant_elim();
|
|
||||||
void apply_distribute_forall();
|
void apply_distribute_forall();
|
||||||
bool apply_bit2int();
|
bool apply_bit2int();
|
||||||
void lift_ite();
|
void lift_ite();
|
||||||
|
|
|
@ -25,19 +25,17 @@ Revision History:
|
||||||
#include"well_sorted.h"
|
#include"well_sorted.h"
|
||||||
#include"used_symbols.h"
|
#include"used_symbols.h"
|
||||||
#include"model_v2_pp.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),
|
model_core(m),
|
||||||
m_simplifier(s),
|
|
||||||
m_afid(m.mk_family_id(symbol("array"))),
|
m_afid(m.mk_family_id(symbol("array"))),
|
||||||
m_eval(*this) {
|
m_eval(*this),
|
||||||
|
m_rewrite(m) {
|
||||||
register_factory(alloc(basic_factory, m));
|
register_factory(alloc(basic_factory, m));
|
||||||
m_user_sort_factory = alloc(user_sort_factory, m);
|
m_user_sort_factory = alloc(user_sort_factory, m);
|
||||||
register_factory(m_user_sort_factory);
|
register_factory(m_user_sort_factory);
|
||||||
|
|
||||||
m_model_partial = model_params(p).partial();
|
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;
|
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 {
|
bool proto_model::is_select_of_model_value(expr* e) const {
|
||||||
return
|
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.
|
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) {
|
bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
|
||||||
if (m_use_new_eval) {
|
m_eval.set_model_completion(model_completion);
|
||||||
m_eval.set_model_completion(model_completion);
|
try {
|
||||||
try {
|
m_eval(e, result);
|
||||||
m_eval(e, result);
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (model_evaluator_exception & ex) {
|
|
||||||
(void)ex;
|
|
||||||
TRACE("model_evaluator", tout << ex.msg() << "\n";);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (model_evaluator_exception & ex) {
|
||||||
bool is_ok = true;
|
(void)ex;
|
||||||
SASSERT(is_well_sorted(m_manager, e));
|
TRACE("model_evaluator", tout << ex.msg() << "\n";);
|
||||||
TRACE("model_eval", tout << mk_pp(e, m_manager) << "\n";
|
return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
if (m_aux_decls.contains(f))
|
||||||
found_aux_fs.insert(f);
|
found_aux_fs.insert(f);
|
||||||
expr_ref new_t(m_manager);
|
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())
|
if (t != new_t.get())
|
||||||
trail.push_back(new_t);
|
trail.push_back(new_t);
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
|
|
|
@ -32,23 +32,22 @@ Revision History:
|
||||||
#include"model_evaluator.h"
|
#include"model_evaluator.h"
|
||||||
#include"value_factory.h"
|
#include"value_factory.h"
|
||||||
#include"plugin_manager.h"
|
#include"plugin_manager.h"
|
||||||
#include"simplifier.h"
|
|
||||||
#include"arith_decl_plugin.h"
|
#include"arith_decl_plugin.h"
|
||||||
#include"func_decl_dependencies.h"
|
#include"func_decl_dependencies.h"
|
||||||
#include"model.h"
|
#include"model.h"
|
||||||
#include"params.h"
|
#include"params.h"
|
||||||
|
#include"th_rewriter.h"
|
||||||
|
|
||||||
class proto_model : public model_core {
|
class proto_model : public model_core {
|
||||||
plugin_manager<value_factory> m_factories;
|
plugin_manager<value_factory> m_factories;
|
||||||
user_sort_factory * m_user_sort_factory;
|
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
|
family_id m_afid; //!< array family id: hack for displaying models in V1.x style
|
||||||
func_decl_set m_aux_decls;
|
func_decl_set m_aux_decls;
|
||||||
ptr_vector<expr> m_tmp;
|
ptr_vector<expr> m_tmp;
|
||||||
model_evaluator m_eval;
|
model_evaluator m_eval;
|
||||||
|
th_rewriter m_rewrite;
|
||||||
|
|
||||||
bool m_model_partial;
|
bool m_model_partial;
|
||||||
bool m_use_new_eval;
|
|
||||||
|
|
||||||
expr * mk_some_interp_for(func_decl * d);
|
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;
|
bool is_select_of_model_value(expr* e) const;
|
||||||
|
|
||||||
public:
|
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() {}
|
virtual ~proto_model() {}
|
||||||
|
|
||||||
void register_factory(value_factory * f) { m_factories.register_plugin(f); }
|
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(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.
|
\brief Return the model associated with the last check command.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace smt {
|
||||||
void model_generator::init_model() {
|
void model_generator::init_model() {
|
||||||
SASSERT(!m_model);
|
SASSERT(!m_model);
|
||||||
// PARAM-TODO smt_params ---> params_ref
|
// 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 it = m_context->begin_theories();
|
||||||
ptr_vector<theory>::const_iterator end = m_context->end_theories();
|
ptr_vector<theory>::const_iterator end = m_context->end_theories();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
|
|
|
@ -315,10 +315,7 @@ namespace smt {
|
||||||
return m_var2enode_lim[m_var2enode_lim.size() - num_scopes];
|
return m_var2enode_lim[m_var2enode_lim.size() - num_scopes];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void display(std::ostream & out) const {
|
virtual void display(std::ostream & out) const = 0;
|
||||||
out << "Theory " << static_cast<int>(get_id()) << typeid(*this).name() << " does not have a display method\n";
|
|
||||||
display_var2enode(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void display_var2enode(std::ostream & out) const;
|
virtual void display_var2enode(std::ostream & out) const;
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace smt {
|
||||||
virtual bool build_models() const {
|
virtual bool build_models() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
virtual void display(std::ostream& out) const {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
theory_dummy(family_id fid, char const * name);
|
theory_dummy(family_id fid, char const * name);
|
||||||
|
|
|
@ -122,6 +122,7 @@ namespace smt {
|
||||||
virtual void new_diseq_eh(theory_var, theory_var) {}
|
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 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 char const * get_name() const { return "seq-empty"; }
|
||||||
|
virtual void display(std::ostream& out) const {}
|
||||||
public:
|
public:
|
||||||
theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {}
|
theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {}
|
||||||
virtual void init_model(model_generator & mg) {
|
virtual void init_model(model_generator & mg) {
|
||||||
|
|
|
@ -94,6 +94,7 @@ namespace smt {
|
||||||
virtual bool internalize_term(app * term) { return false; }
|
virtual bool internalize_term(app * term) { return false; }
|
||||||
virtual void new_eq_eh(theory_var v1, theory_var v2) { }
|
virtual void new_eq_eh(theory_var v1, theory_var v2) { }
|
||||||
virtual void new_diseq_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 {
|
virtual void collect_statistics(::statistics & st) const {
|
||||||
st.update("wmaxsat num blocks", m_stats.m_num_blocks);
|
st.update("wmaxsat num blocks", m_stats.m_num_blocks);
|
||||||
|
|
|
@ -194,7 +194,7 @@ public:
|
||||||
m_use_solver1_results = false;
|
m_use_solver1_results = false;
|
||||||
|
|
||||||
if (get_num_assumptions() != 0 ||
|
if (get_num_assumptions() != 0 ||
|
||||||
num_assumptions > 0 || // assumptions were provided
|
num_assumptions > 0 || // assumptions were provided
|
||||||
m_ignore_solver1) {
|
m_ignore_solver1) {
|
||||||
// must use incremental solver
|
// must use incremental solver
|
||||||
switch_inc_mode();
|
switch_inc_mode();
|
||||||
|
|
|
@ -23,12 +23,11 @@ Notes:
|
||||||
#include"ast_smt2_pp.h"
|
#include"ast_smt2_pp.h"
|
||||||
|
|
||||||
solver_na2as::solver_na2as(ast_manager & m):
|
solver_na2as::solver_na2as(ast_manager & m):
|
||||||
m_manager(m) {
|
m(m),
|
||||||
|
m_assumptions(m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
solver_na2as::~solver_na2as() {
|
solver_na2as::~solver_na2as() {}
|
||||||
restore_assumptions(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void solver_na2as::assert_expr(expr * t, expr * a) {
|
void solver_na2as::assert_expr(expr * t, expr * a) {
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
|
@ -36,20 +35,19 @@ void solver_na2as::assert_expr(expr * t, expr * a) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SASSERT(is_uninterp_const(a));
|
SASSERT(is_uninterp_const(a));
|
||||||
SASSERT(m_manager.is_bool(a));
|
SASSERT(m.is_bool(a));
|
||||||
TRACE("solver_na2as", tout << "asserting\n" << mk_ismt2_pp(t, m_manager) << "\n" << mk_ismt2_pp(a, m_manager) << "\n";);
|
TRACE("solver_na2as", tout << "asserting\n" << mk_ismt2_pp(t, m) << "\n" << mk_ismt2_pp(a, m) << "\n";);
|
||||||
m_manager.inc_ref(a);
|
|
||||||
m_assumptions.push_back(a);
|
m_assumptions.push_back(a);
|
||||||
expr_ref new_t(m_manager);
|
expr_ref new_t(m);
|
||||||
new_t = m_manager.mk_implies(a, t);
|
new_t = m.mk_implies(a, t);
|
||||||
assert_expr(new_t);
|
assert_expr(new_t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct append_assumptions {
|
struct append_assumptions {
|
||||||
ptr_vector<expr> & m_assumptions;
|
expr_ref_vector & m_assumptions;
|
||||||
unsigned m_old_sz;
|
unsigned m_old_sz;
|
||||||
append_assumptions(ptr_vector<expr> & _m_assumptions,
|
append_assumptions(expr_ref_vector & _m_assumptions,
|
||||||
unsigned num_assumptions,
|
unsigned num_assumptions,
|
||||||
expr * const * assumptions):
|
expr * const * assumptions):
|
||||||
m_assumptions(_m_assumptions) {
|
m_assumptions(_m_assumptions) {
|
||||||
|
@ -82,10 +80,6 @@ void solver_na2as::pop(unsigned n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void solver_na2as::restore_assumptions(unsigned old_sz) {
|
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);
|
m_assumptions.shrink(old_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ Notes:
|
||||||
#include"solver.h"
|
#include"solver.h"
|
||||||
|
|
||||||
class solver_na2as : public solver {
|
class solver_na2as : public solver {
|
||||||
ast_manager & m_manager;
|
ast_manager & m;
|
||||||
ptr_vector<expr> m_assumptions;
|
expr_ref_vector m_assumptions;
|
||||||
unsigned_vector m_scopes;
|
unsigned_vector m_scopes;
|
||||||
void restore_assumptions(unsigned old_sz);
|
void restore_assumptions(unsigned old_sz);
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -60,7 +60,7 @@ class nla2bv_tactic : public tactic {
|
||||||
expr_ref_vector m_trail;
|
expr_ref_vector m_trail;
|
||||||
unsigned m_num_bits;
|
unsigned m_num_bits;
|
||||||
unsigned m_default_bv_size;
|
unsigned m_default_bv_size;
|
||||||
ref<filter_model_converter> m_fmc;
|
filter_model_converter_ref m_fmc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
imp(ast_manager & m, params_ref const& p):
|
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_lowers;
|
||||||
obj_map<app, numeral> m_unsigned_uppers;
|
obj_map<app, numeral> m_unsigned_uppers;
|
||||||
ref<bv_size_reduction_mc> m_mc;
|
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;
|
scoped_ptr<expr_replacer> m_replacer;
|
||||||
bool m_produce_models;
|
bool m_produce_models;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ Revision History:
|
||||||
|
|
||||||
class propagate_values_tactic : public tactic {
|
class propagate_values_tactic : public tactic {
|
||||||
struct imp {
|
struct imp {
|
||||||
ast_manager & m_manager;
|
ast_manager & m;
|
||||||
th_rewriter m_r;
|
th_rewriter m_r;
|
||||||
scoped_ptr<expr_substitution> m_subst;
|
scoped_ptr<expr_substitution> m_subst;
|
||||||
goal * m_goal;
|
goal * m_goal;
|
||||||
|
@ -36,13 +36,15 @@ class propagate_values_tactic : public tactic {
|
||||||
bool m_modified;
|
bool m_modified;
|
||||||
|
|
||||||
imp(ast_manager & m, params_ref const & p):
|
imp(ast_manager & m, params_ref const & p):
|
||||||
m_manager(m),
|
m(m),
|
||||||
m_r(m, p),
|
m_r(m, p),
|
||||||
m_goal(0),
|
m_goal(0),
|
||||||
m_occs(m, true /* track atoms */) {
|
m_occs(m, true /* track atoms */) {
|
||||||
updt_params_core(p);
|
updt_params_core(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~imp() { }
|
||||||
|
|
||||||
void updt_params_core(params_ref const & p) {
|
void updt_params_core(params_ref const & p) {
|
||||||
m_max_rounds = p.get_uint("max_rounds", 4);
|
m_max_rounds = p.get_uint("max_rounds", 4);
|
||||||
}
|
}
|
||||||
|
@ -52,31 +54,27 @@ class propagate_values_tactic : public tactic {
|
||||||
updt_params_core(p);
|
updt_params_core(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_manager & m() const { return m_manager; }
|
|
||||||
|
|
||||||
|
|
||||||
bool is_shared(expr * t) {
|
bool is_shared(expr * t) {
|
||||||
return m_occs.is_shared(t);
|
return m_occs.is_shared(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_shared_neg(expr * t, expr * & atom) {
|
bool is_shared_neg(expr * t, expr * & atom) {
|
||||||
if (!m().is_not(t))
|
if (!m.is_not(t, atom))
|
||||||
return false;
|
return false;
|
||||||
atom = to_app(t)->get_arg(0);
|
|
||||||
return is_shared(atom);
|
return is_shared(atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_shared_eq(expr * t, expr * & lhs, expr * & value) {
|
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;
|
return false;
|
||||||
expr * arg1 = to_app(t)->get_arg(0);
|
if (m.is_value(arg1) && is_shared(arg2)) {
|
||||||
expr * arg2 = to_app(t)->get_arg(1);
|
|
||||||
if (m().is_value(arg1) && is_shared(arg2)) {
|
|
||||||
lhs = arg2;
|
lhs = arg2;
|
||||||
value = arg1;
|
value = arg1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m().is_value(arg2) && is_shared(arg1)) {
|
if (m.is_value(arg2) && is_shared(arg1)) {
|
||||||
lhs = arg1;
|
lhs = arg1;
|
||||||
value = arg2;
|
value = arg2;
|
||||||
return true;
|
return true;
|
||||||
|
@ -87,15 +85,15 @@ class propagate_values_tactic : public tactic {
|
||||||
void push_result(expr * new_curr, proof * new_pr) {
|
void push_result(expr * new_curr, proof * new_pr) {
|
||||||
if (m_goal->proofs_enabled()) {
|
if (m_goal->proofs_enabled()) {
|
||||||
proof * pr = m_goal->pr(m_idx);
|
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()) {
|
if (m_goal->unsat_core_enabled()) {
|
||||||
new_d = m_goal->dep(m_idx);
|
new_d = m_goal->dep(m_idx);
|
||||||
expr_dependency * used_d = m_r.get_used_dependencies();
|
expr_dependency * used_d = m_r.get_used_dependencies();
|
||||||
if (used_d != 0) {
|
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();
|
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);
|
m_goal->update(m_idx, new_curr, new_pr, new_d);
|
||||||
|
|
||||||
if (is_shared(new_curr)) {
|
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;
|
expr * atom;
|
||||||
if (is_shared_neg(new_curr, 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;
|
expr * lhs, * value;
|
||||||
if (is_shared_eq(new_curr, 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);
|
m_subst->insert(lhs, value, new_pr, new_d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_current() {
|
void process_current() {
|
||||||
expr * curr = m_goal->form(m_idx);
|
expr * curr = m_goal->form(m_idx);
|
||||||
expr_ref new_curr(m());
|
expr_ref new_curr(m);
|
||||||
proof_ref new_pr(m());
|
proof_ref new_pr(m);
|
||||||
|
|
||||||
if (!m_subst->empty()) {
|
if (!m_subst->empty()) {
|
||||||
m_r(curr, new_curr, new_pr);
|
m_r(curr, new_curr, new_pr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
new_curr = curr;
|
new_curr = curr;
|
||||||
if (m().proofs_enabled())
|
if (m.proofs_enabled())
|
||||||
new_pr = m().mk_reflexivity(curr);
|
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);
|
push_result(new_curr, new_pr);
|
||||||
|
|
||||||
if (new_curr != curr)
|
if (new_curr != curr)
|
||||||
|
@ -148,25 +146,26 @@ class propagate_values_tactic : public tactic {
|
||||||
m_goal = g.get();
|
m_goal = g.get();
|
||||||
|
|
||||||
bool forward = true;
|
bool forward = true;
|
||||||
expr_ref new_curr(m());
|
expr_ref new_curr(m);
|
||||||
proof_ref new_pr(m());
|
proof_ref new_pr(m);
|
||||||
unsigned size = m_goal->size();
|
unsigned size = m_goal->size();
|
||||||
m_idx = 0;
|
m_idx = 0;
|
||||||
m_modified = false;
|
m_modified = false;
|
||||||
unsigned round = 0;
|
unsigned round = 0;
|
||||||
|
|
||||||
|
|
||||||
if (m_goal->inconsistent())
|
if (m_goal->inconsistent())
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (m_max_rounds == 0)
|
if (m_max_rounds == 0)
|
||||||
goto end;
|
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_r.set_substitution(m_subst.get());
|
||||||
m_occs(*m_goal);
|
m_occs(*m_goal);
|
||||||
|
|
||||||
while (true) {
|
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) {
|
if (forward) {
|
||||||
for (; m_idx < size; m_idx++) {
|
for (; m_idx < size; m_idx++) {
|
||||||
process_current();
|
process_current();
|
||||||
|
@ -255,15 +254,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void cleanup() {
|
virtual void cleanup() {
|
||||||
ast_manager & m = m_imp->m();
|
ast_manager & m = m_imp->m;
|
||||||
imp * d = alloc(imp, m, m_params);
|
dealloc(m_imp);
|
||||||
std::swap(d, m_imp);
|
m_imp = alloc(imp, m, m_params);
|
||||||
dealloc(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tactic * mk_propagate_values_tactic(ast_manager & m, params_ref const & p) {
|
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"smt_tactic.h"
|
||||||
#include"nnf_tactic.h"
|
#include"nnf_tactic.h"
|
||||||
#include"qe_tactic.h"
|
#include"qe_tactic.h"
|
||||||
|
#include"nlqsat.h"
|
||||||
#include"qfnra_nlsat_tactic.h"
|
#include"qfnra_nlsat_tactic.h"
|
||||||
|
#include"qe_lite.h"
|
||||||
#include"probe_arith.h"
|
#include"probe_arith.h"
|
||||||
|
|
||||||
tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) {
|
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),
|
return and_then(mk_simplify_tactic(m, p),
|
||||||
mk_nnf_tactic(m, p),
|
mk_nnf_tactic(m, p),
|
||||||
mk_propagate_values_tactic(m, p),
|
mk_propagate_values_tactic(m, p),
|
||||||
|
//mk_qe_lite_tactic(m),
|
||||||
mk_qe_tactic(m, p),
|
mk_qe_tactic(m, p),
|
||||||
cond(mk_is_qfnra_probe(),
|
cond(mk_is_qfnra_probe(),
|
||||||
or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000),
|
or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000),
|
||||||
try_for(mk_qfnra_nlsat_tactic(m, p1), 10000),
|
try_for(mk_qfnra_nlsat_tactic(m, p1), 10000),
|
||||||
mk_qfnra_nlsat_tactic(m, p2)),
|
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"elim_uncnstr_tactic.h"
|
||||||
#include"qe_tactic.h"
|
#include"qe_tactic.h"
|
||||||
#include"qe_sat_tactic.h"
|
#include"qe_sat_tactic.h"
|
||||||
|
#include"qe_lite.h"
|
||||||
|
#include"qsat.h"
|
||||||
|
#include"nlqsat.h"
|
||||||
#include"ctx_simplify_tactic.h"
|
#include"ctx_simplify_tactic.h"
|
||||||
#include"smt_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);
|
ctx_simp_p.set_uint("max_steps", 5000000);
|
||||||
|
|
||||||
tactic * solve_eqs;
|
tactic * solve_eqs;
|
||||||
if (disable_gaussian)
|
if (disable_gaussian) {
|
||||||
solve_eqs = mk_skip_tactic();
|
solve_eqs = mk_skip_tactic();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
solve_eqs = when(mk_not(mk_has_pattern_probe()), mk_solve_eqs_tactic(m));
|
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.
|
// remark: investigate if gaussian elimination is useful when patterns are not provided.
|
||||||
return and_then(mk_simplify_tactic(m),
|
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),
|
using_params(mk_simplify_tactic(m), pull_ite_p),
|
||||||
solve_eqs,
|
solve_eqs,
|
||||||
mk_elim_uncnstr_tactic(m),
|
mk_elim_uncnstr_tactic(m),
|
||||||
|
mk_qe_lite_tactic(m),
|
||||||
mk_simplify_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) {
|
tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) {
|
||||||
|
#if 0
|
||||||
tactic * st = and_then(mk_quant_preprocessor(m),
|
tactic * st = and_then(mk_quant_preprocessor(m),
|
||||||
or_else(try_for(mk_smt_tactic(), 100),
|
or_else(try_for(mk_smt_tactic(), 100),
|
||||||
try_for(qe::mk_sat_tactic(m), 1000),
|
try_for(qe::mk_sat_tactic(m), 1000),
|
||||||
try_for(mk_smt_tactic(), 1000),
|
try_for(mk_smt_tactic(), 1000),
|
||||||
and_then(mk_qe_tactic(m), mk_smt_tactic())
|
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);
|
st->updt_params(p);
|
||||||
return st;
|
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) {
|
tactic * mk_lira_tactic(ast_manager & m, params_ref const & p) {
|
||||||
return mk_lra_tactic(m, p);
|
return mk_lra_tactic(m, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ Notes:
|
||||||
#include"nlsat_evaluator.h"
|
#include"nlsat_evaluator.h"
|
||||||
#include"nlsat_solver.h"
|
#include"nlsat_solver.h"
|
||||||
#include"util.h"
|
#include"util.h"
|
||||||
|
#include"nlsat_explain.h"
|
||||||
|
#include"polynomial_cache.h"
|
||||||
#include"rlimit.h"
|
#include"rlimit.h"
|
||||||
|
|
||||||
nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1,
|
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) {
|
bool check_num_intervals = true) {
|
||||||
nlsat::interval_set_manager & ism = s1.m();
|
nlsat::interval_set_manager & ism = s1.m();
|
||||||
nlsat::interval_set_ref r(ism);
|
nlsat::interval_set_ref r(ism);
|
||||||
std::cout << "------------------\n";
|
|
||||||
std::cout << "s1: " << s1 << "\n";
|
std::cout << "s1: " << s1 << "\n";
|
||||||
std::cout << "s2: " << s2 << "\n";
|
std::cout << "s2: " << s2 << "\n";
|
||||||
r = ism.mk_union(s1, s2);
|
r = ism.mk_union(s1, s2);
|
||||||
|
@ -277,10 +278,12 @@ static void tst5() {
|
||||||
nlsat::assignment as(am);
|
nlsat::assignment as(am);
|
||||||
small_object_allocator allocator;
|
small_object_allocator allocator;
|
||||||
nlsat::interval_set_manager ism(am, 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;
|
nlsat::var x0, x1;
|
||||||
x0 = pm.mk_var();
|
x0 = pm.mk_var();
|
||||||
x1 = pm.mk_var();
|
x1 = pm.mk_var();
|
||||||
|
nlsat::interval_set_ref i(ism);
|
||||||
|
|
||||||
polynomial_ref p(pm);
|
polynomial_ref p(pm);
|
||||||
polynomial_ref _x0(pm), _x1(pm);
|
polynomial_ref _x0(pm), _x1(pm);
|
||||||
_x0 = pm.mk_polynomial(x0);
|
_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::bool_var b = s.mk_ineq_atom(nlsat::atom::GT, 1, _p, is_even);
|
||||||
nlsat::atom * a = s.bool_var2atom(b);
|
nlsat::atom * a = s.bool_var2atom(b);
|
||||||
SASSERT(a != 0);
|
SASSERT(a != 0);
|
||||||
nlsat::interval_set_ref i(ism);
|
|
||||||
scoped_anum zero(am);
|
scoped_anum zero(am);
|
||||||
am.set(zero, 0);
|
am.set(zero, 0);
|
||||||
as.set(0, zero);
|
as.set(0, zero);
|
||||||
|
@ -302,8 +304,414 @@ static void tst5() {
|
||||||
std::cout << "2) " << i << "\n";
|
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() {
|
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();
|
tst5();
|
||||||
|
std::cout << "------------------\n";
|
||||||
tst4();
|
tst4();
|
||||||
|
std::cout << "------------------\n";
|
||||||
tst3();
|
tst3();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ Copyright (c) 2015 Microsoft Corporation
|
||||||
#include "reg_decl_plugins.h"
|
#include "reg_decl_plugins.h"
|
||||||
#include "arith_rewriter.h"
|
#include "arith_rewriter.h"
|
||||||
#include "ast_pp.h"
|
#include "ast_pp.h"
|
||||||
#include "qe_util.h"
|
|
||||||
#include "smt_context.h"
|
#include "smt_context.h"
|
||||||
#include "expr_abstract.h"
|
#include "expr_abstract.h"
|
||||||
|
#include "expr_safe_replace.h"
|
||||||
|
|
||||||
static expr_ref parse_fml(ast_manager& m, char const* str) {
|
static expr_ref parse_fml(ast_manager& m, char const* str) {
|
||||||
expr_ref result(m);
|
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 t Real)\n"
|
||||||
<< "(declare-const a Real)\n"
|
<< "(declare-const a Real)\n"
|
||||||
<< "(declare-const b 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";
|
<< "(assert " << str << ")\n";
|
||||||
std::istringstream is(buffer.str());
|
std::istringstream is(buffer.str());
|
||||||
VERIFY(parse_smt2_commands(ctx, is));
|
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* 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* 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* 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))\
|
static char const* example6 = "(and (<= 0 (+ x z))\
|
||||||
(>= y x) \
|
(>= y x) \
|
||||||
|
@ -51,30 +58,175 @@ static char const* example6 = "(and (<= 0 (+ x z))\
|
||||||
(>= x 0.0)\
|
(>= x 0.0)\
|
||||||
(<= x 1.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;
|
smt_params params;
|
||||||
params.m_model = true;
|
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;
|
ast_manager m;
|
||||||
reg_decl_plugins(m);
|
reg_decl_plugins(m);
|
||||||
arith_util a(m);
|
arith_util a(m);
|
||||||
expr_ref fml = parse_fml(m, ex);
|
expr_ref fml = parse_fml(m, ex);
|
||||||
app_ref_vector vars(m);
|
symbol x_name("x");
|
||||||
expr_ref_vector lits(m);
|
sort_ref x_sort(a.mk_real(), m);
|
||||||
vars.push_back(m.mk_const(symbol("x"), a.mk_real()));
|
app_ref var(m.mk_const(x_name, x_sort), m);
|
||||||
flatten_and(fml, lits);
|
test(var, fml);
|
||||||
|
}
|
||||||
|
|
||||||
smt::context ctx(m, params);
|
static void testI(char const *ex) {
|
||||||
ctx.assert_expr(fml);
|
ast_manager m;
|
||||||
lbool result = ctx.check();
|
reg_decl_plugins(m);
|
||||||
SASSERT(result == l_true);
|
arith_util a(m);
|
||||||
ref<model> md;
|
expr_ref fml = parse_fml(m, ex);
|
||||||
ctx.get_model(md);
|
symbol x_name("i");
|
||||||
expr_ref pr = qe::arith_project(*md, vars, lits);
|
sort_ref x_sort(a.mk_int(), m);
|
||||||
|
app_ref var(m.mk_const(x_name, x_sort), m);
|
||||||
|
test(var, fml);
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << mk_pp(fml, m) << "\n";
|
static expr_ref_vector mk_ineqs(app* x, app* y, app_ref_vector const& nums) {
|
||||||
std::cout << mk_pp(pr, m) << "\n";
|
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) {
|
static void test2(char const *ex) {
|
||||||
|
@ -102,7 +254,7 @@ static void test2(char const *ex) {
|
||||||
|
|
||||||
std::cout << mk_pp(fml, m) << "\n";
|
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);
|
expr_ref_vector bound(m);
|
||||||
ptr_vector<sort> sorts;
|
ptr_vector<sort> sorts;
|
||||||
svector<symbol> names;
|
svector<symbol> names;
|
||||||
|
@ -114,7 +266,10 @@ static void test2(char const *ex) {
|
||||||
expr_abstract(m, 0, bound.size(), bound.c_ptr(), fml, fml2);
|
expr_abstract(m, 0, bound.size(), bound.c_ptr(), fml, fml2);
|
||||||
fml2 = m.mk_exists(bound.size(), sorts.c_ptr(), names.c_ptr(), fml2);
|
fml2 = m.mk_exists(bound.size(), sorts.c_ptr(), names.c_ptr(), fml2);
|
||||||
qe::expr_quant_elim qe(m, params);
|
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);
|
qe(m.mk_true(), fml2, pr2);
|
||||||
std::cout << mk_pp(pr1, m) << "\n";
|
std::cout << mk_pp(pr1, m) << "\n";
|
||||||
std::cout << mk_pp(pr2, m) << "\n";
|
std::cout << mk_pp(pr2, m) << "\n";
|
||||||
|
@ -131,11 +286,17 @@ static void test2(char const *ex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_qe_arith() {
|
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);
|
test2(example6);
|
||||||
return;
|
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(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); }
|
bool contains(obj_pair const & p) const { return m_set.contains(p); }
|
||||||
void reset() { m_set.reset(); }
|
void reset() { m_set.reset(); }
|
||||||
|
bool empty() const { return m_set.empty(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -69,6 +69,7 @@ void small_object_allocator::reset() {
|
||||||
#define MASK ((1 << PTR_ALIGNMENT) - 1)
|
#define MASK ((1 << PTR_ALIGNMENT) - 1)
|
||||||
|
|
||||||
void small_object_allocator::deallocate(size_t size, void * p) {
|
void small_object_allocator::deallocate(size_t size, void * p) {
|
||||||
|
if (size == 0) return;
|
||||||
#if defined(Z3DEBUG) && !defined(_WINDOWS)
|
#if defined(Z3DEBUG) && !defined(_WINDOWS)
|
||||||
// Valgrind friendly
|
// Valgrind friendly
|
||||||
memory::deallocate(p);
|
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) {
|
void * small_object_allocator::allocate(size_t size) {
|
||||||
|
if (size == 0) return 0;
|
||||||
#if defined(Z3DEBUG) && !defined(_WINDOWS)
|
#if defined(Z3DEBUG) && !defined(_WINDOWS)
|
||||||
// Valgrind friendly
|
// Valgrind friendly
|
||||||
return memory::allocate(size);
|
return memory::allocate(size);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue