mirror of
https://github.com/Z3Prover/z3
synced 2025-04-10 19:27:06 +00:00
Merge branch 'master' of https://github.com/Z3Prover/z3
This commit is contained in:
commit
ef9486913b
contrib/cmake
scripts
src
ast
ast_smt2_pp.cppexpr_functors.h
fpa
fpa_decl_plugin.cppfpa_decl_plugin.hpb_decl_plugin.cpppb_decl_plugin.hrewriter
cmd_context
model
sat
smt
tactic
test
|
@ -1,4 +1,9 @@
|
|||
# FIXME: We should build this as an external project and consume
|
||||
# Z3 as `find_package(z3 CONFIG)`.
|
||||
add_executable(cpp_example EXCLUDE_FROM_ALL example.cpp)
|
||||
target_link_libraries(cpp_example PRIVATE libz3)
|
||||
target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api")
|
||||
target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++")
|
||||
if (NOT BUILD_LIBZ3_SHARED)
|
||||
z3_append_linker_flag_list_to_target(cpp_example ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
|
||||
endif()
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
# FIXME: We should build this as an external project and consume
|
||||
# Z3 as `find_package(z3 CONFIG)`.
|
||||
add_executable(c_example EXCLUDE_FROM_ALL test_capi.c)
|
||||
target_link_libraries(c_example PRIVATE libz3)
|
||||
target_include_directories(c_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api")
|
||||
# This is needed for when libz3 is built as a static library
|
||||
if (NOT BUILD_LIBZ3_SHARED)
|
||||
z3_append_linker_flag_list_to_target(c_example ${Z3_DEPENDENT_EXTRA_C_LINK_FLAGS})
|
||||
endif()
|
||||
|
|
|
@ -136,9 +136,10 @@ if (NOT MSVC)
|
|||
set_target_properties(libz3 PROPERTIES OUTPUT_NAME z3)
|
||||
endif()
|
||||
|
||||
# Using INTERFACE means that targets that try link against libz3 will
|
||||
# automatically link against the libs in Z3_DEPENDENT_LIBS
|
||||
target_link_libraries(libz3 INTERFACE ${Z3_DEPENDENT_LIBS})
|
||||
# The `PRIVATE` usage requirement is specified so that when building Z3 as a
|
||||
# shared library the dependent libraries are specified on the link command line
|
||||
# so that if those are also shared libraries they are referenced by `libz3.so`.
|
||||
target_link_libraries(libz3 PRIVATE ${Z3_DEPENDENT_LIBS})
|
||||
|
||||
z3_append_linker_flag_list_to_target(libz3 ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ elseif (DOTNET_TOOLCHAIN_IS_MONO)
|
|||
# We need to give the assembly a strong name so that it can be installed
|
||||
# into the GAC.
|
||||
list(APPEND CSC_FLAGS
|
||||
"/keyfile:${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.mono.snk"
|
||||
"/keyfile:${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.snk"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown .NET toolchain")
|
||||
|
|
|
@ -110,7 +110,9 @@ set(Z3_JAVA_JAR_SOURCE_FILES
|
|||
BitVecSort.java
|
||||
BoolExpr.java
|
||||
BoolSort.java
|
||||
ConstructorDecRefQueue.java
|
||||
Constructor.java
|
||||
ConstructorListDecRefQueue.java
|
||||
ConstructorList.java
|
||||
Context.java
|
||||
DatatypeExpr.java
|
||||
|
@ -136,7 +138,6 @@ set(Z3_JAVA_JAR_SOURCE_FILES
|
|||
GoalDecRefQueue.java
|
||||
Goal.java
|
||||
IDecRefQueue.java
|
||||
IDisposable.java
|
||||
InterpolationContext.java
|
||||
IntExpr.java
|
||||
IntNum.java
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
z3_add_component(fpa
|
||||
SOURCES
|
||||
bv2fpa_converter.cpp
|
||||
fpa2bv_converter.cpp
|
||||
fpa2bv_rewriter.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
ast
|
||||
simplifier
|
||||
model
|
||||
util
|
||||
PYG_FILES
|
||||
fpa2bv_rewriter_params.pyg
|
||||
|
|
|
@ -12,6 +12,7 @@ z3_add_component(rewriter
|
|||
expr_replacer.cpp
|
||||
expr_safe_replace.cpp
|
||||
factor_rewriter.cpp
|
||||
fd_rewriter.cpp
|
||||
fpa_rewriter.cpp
|
||||
label_rewriter.cpp
|
||||
mk_simplified_app.cpp
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
z3_add_component(portfolio
|
||||
SOURCES
|
||||
default_tactic.cpp
|
||||
fd_solver.cpp
|
||||
smt_strategic_solver.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
aig_tactic
|
||||
|
|
|
@ -42,6 +42,7 @@ add_executable(test-z3
|
|||
factor_rewriter.cpp
|
||||
fixed_bit_vector.cpp
|
||||
for_each_file.cpp
|
||||
get_consequences.cpp
|
||||
get_implied_equalities.cpp
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/gparams_register_modules.cpp"
|
||||
hashtable.cpp
|
||||
|
|
|
@ -45,7 +45,7 @@ def init_project_def():
|
|||
# Simplifier module will be deleted in the future.
|
||||
# It has been replaced with rewriter module.
|
||||
add_lib('simplifier', ['rewriter'], 'ast/simplifier')
|
||||
add_lib('fpa', ['ast', 'util', 'simplifier'], 'ast/fpa')
|
||||
add_lib('fpa', ['ast', 'util', 'simplifier', 'model'], 'ast/fpa')
|
||||
add_lib('macros', ['simplifier'], 'ast/macros')
|
||||
add_lib('pattern', ['normal_forms', 'smt2parser', 'simplifier'], 'ast/pattern')
|
||||
add_lib('bit_blaster', ['rewriter', 'simplifier'], 'ast/rewriter/bit_blaster')
|
||||
|
|
|
@ -1205,13 +1205,16 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num
|
|||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) {
|
||||
smt2_pp_environment_dbg env(p.m_manager);
|
||||
smt2_pp_environment_dbg env(p.m_manager);
|
||||
if (is_expr(p.m_ast)) {
|
||||
ast_smt2_pp(out, to_expr(p.m_ast), env, p.m_params, p.m_indent, p.m_num_vars, p.m_var_prefix);
|
||||
}
|
||||
else if (is_sort(p.m_ast)) {
|
||||
ast_smt2_pp(out, to_sort(p.m_ast), env, p.m_params, p.m_indent);
|
||||
}
|
||||
else if (p.m_ast == 0) {
|
||||
out << "null";
|
||||
}
|
||||
else {
|
||||
SASSERT(is_func_decl(p.m_ast));
|
||||
ast_smt2_pp(out, to_func_decl(p.m_ast), env, p.m_params, p.m_indent);
|
||||
|
|
|
@ -31,6 +31,14 @@ public:
|
|||
virtual ~i_expr_pred() {}
|
||||
};
|
||||
|
||||
|
||||
class i_sort_pred {
|
||||
public:
|
||||
virtual bool operator()(sort* s) = 0;
|
||||
virtual ~i_sort_pred() {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
\brief Memoizing predicate functor on sub-expressions.
|
||||
|
||||
|
|
551
src/ast/fpa/bv2fpa_converter.cpp
Normal file
551
src/ast/fpa/bv2fpa_converter.cpp
Normal file
|
@ -0,0 +1,551 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv2fpa_converter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Model conversion for fpa2bv_converter
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2016-10-15
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include<math.h>
|
||||
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"well_sorted.h"
|
||||
#include"th_rewriter.h"
|
||||
#include"fpa_rewriter.h"
|
||||
|
||||
#include"bv2fpa_converter.h"
|
||||
|
||||
|
||||
bv2fpa_converter::bv2fpa_converter(ast_manager & m) :
|
||||
m(m),
|
||||
m_fpa_util(m),
|
||||
m_bv_util(m),
|
||||
m_th_rw(m) {
|
||||
}
|
||||
|
||||
bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) :
|
||||
m(m),
|
||||
m_fpa_util(m),
|
||||
m_bv_util(m),
|
||||
m_th_rw(m) {
|
||||
for (obj_map<func_decl, expr*>::iterator it = conv.m_const2bv.begin();
|
||||
it != conv.m_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
m_const2bv.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
for (obj_map<func_decl, expr*>::iterator it = conv.m_rm_const2bv.begin();
|
||||
it != conv.m_rm_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
m_rm_const2bv.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = conv.m_uf2bvuf.begin();
|
||||
it != conv.m_uf2bvuf.end();
|
||||
it++)
|
||||
{
|
||||
m_uf2bvuf.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_specials.begin();
|
||||
it != conv.m_min_max_specials.end();
|
||||
it++) {
|
||||
m_specials.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value.first);
|
||||
m.inc_ref(it->m_value.second);
|
||||
}
|
||||
}
|
||||
|
||||
bv2fpa_converter::~bv2fpa_converter() {
|
||||
dec_ref_map_key_values(m, m_const2bv);
|
||||
dec_ref_map_key_values(m, m_rm_const2bv);
|
||||
dec_ref_map_key_values(m, m_uf2bvuf);
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
m.dec_ref(it->m_key);
|
||||
m.dec_ref(it->m_value.first);
|
||||
m.dec_ref(it->m_value.second);
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref bv2fpa_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) {
|
||||
unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager();
|
||||
unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager();
|
||||
|
||||
expr_ref res(m);
|
||||
mpf fp_val;
|
||||
|
||||
unsigned ebits = m_fpa_util.get_ebits(s);
|
||||
unsigned sbits = m_fpa_util.get_sbits(s);
|
||||
|
||||
unsigned sgn_sz = 1;
|
||||
unsigned exp_sz = ebits;
|
||||
unsigned sig_sz = sbits - 1;
|
||||
|
||||
rational sgn_q(0), sig_q(0), exp_q(0);
|
||||
|
||||
if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz);
|
||||
if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz);
|
||||
if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz);
|
||||
|
||||
// un-bias exponent
|
||||
rational exp_unbiased_q;
|
||||
exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 1);
|
||||
|
||||
mpz sig_z; mpf_exp_t exp_z;
|
||||
mpzm.set(sig_z, sig_q.to_mpq().numerator());
|
||||
exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator());
|
||||
|
||||
m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z);
|
||||
|
||||
mpzm.del(sig_z);
|
||||
|
||||
res = m_fpa_util.mk_value(fp_val);
|
||||
|
||||
TRACE("bv2fpa", tout << "[" << mk_ismt2_pp(sgn, m) <<
|
||||
" " << mk_ismt2_pp(exp, m) <<
|
||||
" " << mk_ismt2_pp(sig, m) << "] == " <<
|
||||
mk_ismt2_pp(res, m) << std::endl;);
|
||||
m_fpa_util.fm().del(fp_val);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref bv2fpa_converter::convert_bv2fp(model_core * mc, sort * s, app * bv) {
|
||||
SASSERT(m_bv_util.is_bv(bv));
|
||||
|
||||
unsigned ebits = m_fpa_util.get_ebits(s);
|
||||
unsigned sbits = m_fpa_util.get_sbits(s);
|
||||
unsigned bv_sz = sbits + ebits;
|
||||
|
||||
expr_ref bv_num(m);
|
||||
if (m_bv_util.is_numeral(bv))
|
||||
bv_num = bv;
|
||||
else if (!mc->eval(bv->get_decl(), bv_num))
|
||||
bv_num = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(bv));
|
||||
|
||||
expr_ref sgn(m), exp(m), sig(m);
|
||||
sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv_num);
|
||||
exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv_num);
|
||||
sig = m_bv_util.mk_extract(sbits - 2, 0, bv_num);
|
||||
|
||||
expr_ref v_sgn(m), v_exp(m), v_sig(m);
|
||||
m_th_rw(sgn, v_sgn);
|
||||
m_th_rw(exp, v_exp);
|
||||
m_th_rw(sig, v_sig);
|
||||
|
||||
return convert_bv2fp(s, v_sgn, v_exp, v_sig);
|
||||
}
|
||||
|
||||
expr_ref bv2fpa_converter::convert_bv2rm(expr * bv_rm) {
|
||||
expr_ref res(m);
|
||||
rational bv_val(0);
|
||||
unsigned sz = 0;
|
||||
|
||||
if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) {
|
||||
SASSERT(bv_val.is_uint64());
|
||||
switch (bv_val.get_uint64()) {
|
||||
case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break;
|
||||
case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break;
|
||||
case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break;
|
||||
case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break;
|
||||
case BV_RM_TO_ZERO:
|
||||
default: res = m_fpa_util.mk_round_toward_zero();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref bv2fpa_converter::convert_bv2rm(model_core * mc, app * val) {
|
||||
expr_ref res(m);
|
||||
|
||||
if (val) {
|
||||
expr_ref eval_v(m);
|
||||
if (m_bv_util.is_numeral(val))
|
||||
res = convert_bv2rm(val);
|
||||
else if (mc->eval(val->get_decl(), eval_v))
|
||||
res = convert_bv2rm(eval_v);
|
||||
else
|
||||
res = m_fpa_util.mk_round_toward_zero();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref bv2fpa_converter::rebuild_floats(model_core * mc, sort * s, app * e) {
|
||||
expr_ref result(m);
|
||||
TRACE("bv2fpa", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for ";
|
||||
if (e) tout << mk_ismt2_pp(e, m);
|
||||
else tout << "nil";
|
||||
tout << std::endl; );
|
||||
|
||||
if (m_fpa_util.is_float(s)) {
|
||||
if (e == 0)
|
||||
result = m_fpa_util.mk_pzero(s);
|
||||
else if (m_fpa_util.is_numeral(e))
|
||||
result = e;
|
||||
else {
|
||||
SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s)));
|
||||
result = convert_bv2fp(mc, s, e);
|
||||
}
|
||||
}
|
||||
else if (m_fpa_util.is_rm(s)) {
|
||||
if (e == 0)
|
||||
result = m_fpa_util.mk_round_toward_zero();
|
||||
else if (m_fpa_util.is_rm_numeral(e))
|
||||
result = e;
|
||||
else {
|
||||
SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3);
|
||||
result = convert_bv2rm(mc, e);
|
||||
}
|
||||
}
|
||||
else if (is_app(e)) {
|
||||
app * a = to_app(e);
|
||||
expr_ref_vector new_args(m);
|
||||
for (unsigned i = 0; i < a->get_num_args(); i++)
|
||||
new_args.push_back(rebuild_floats(mc, a->get_decl()->get_domain()[i], to_app(a->get_arg(i))));
|
||||
result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) {
|
||||
SASSERT(f->get_arity() == 0);
|
||||
array_util arr_util(m);
|
||||
|
||||
array_model am(m);
|
||||
sort_ref_vector array_domain(m);
|
||||
unsigned arity = f->get_range()->get_num_parameters()-1;
|
||||
|
||||
expr_ref as_arr_mdl(m);
|
||||
as_arr_mdl = mc->get_const_interp(bv_f);
|
||||
if (as_arr_mdl == 0) return am;
|
||||
TRACE("bv2fpa", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;);
|
||||
SASSERT(arr_util.is_as_array(as_arr_mdl));
|
||||
for (unsigned i = 0; i < arity; i++)
|
||||
array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast()));
|
||||
sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast());
|
||||
|
||||
bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl));
|
||||
|
||||
am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng);
|
||||
am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f);
|
||||
am.bv_fd = bv_f;
|
||||
am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd);
|
||||
return am;
|
||||
}
|
||||
|
||||
func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) {
|
||||
SASSERT(f->get_arity() > 0);
|
||||
func_interp * result = 0;
|
||||
sort * rng = f->get_range();
|
||||
sort * const * dmn = f->get_domain();
|
||||
|
||||
unsigned arity = bv_f->get_arity();
|
||||
func_interp * bv_fi = mc->get_func_interp(bv_f);
|
||||
|
||||
if (bv_fi != 0) {
|
||||
fpa_rewriter rw(m);
|
||||
expr_ref ai(m);
|
||||
result = alloc(func_interp, m, arity);
|
||||
|
||||
for (unsigned i = 0; i < bv_fi->num_entries(); i++) {
|
||||
func_entry const * bv_fe = bv_fi->get_entry(i);
|
||||
expr * const * bv_args = bv_fe->get_args();
|
||||
expr_ref_buffer new_args(m);
|
||||
|
||||
for (unsigned j = 0; j < arity; j++) {
|
||||
sort * ft_dj = dmn[j];
|
||||
expr * bv_aj = bv_args[j];
|
||||
ai = rebuild_floats(mc, ft_dj, to_app(bv_aj));
|
||||
m_th_rw(ai);
|
||||
new_args.push_back(ai);
|
||||
}
|
||||
|
||||
expr_ref bv_fres(m), ft_fres(m);
|
||||
bv_fres = bv_fe->get_result();
|
||||
ft_fres = rebuild_floats(mc, rng, to_app(bv_fres));
|
||||
m_th_rw(ft_fres);
|
||||
result->insert_new_entry(new_args.c_ptr(), ft_fres);
|
||||
}
|
||||
|
||||
app_ref bv_els(m);
|
||||
expr_ref ft_els(m);
|
||||
bv_els = (app*)bv_fi->get_else();
|
||||
ft_els = rebuild_floats(mc, rng, bv_els);
|
||||
m_th_rw(ft_els);
|
||||
result->set_else(ft_els);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
|
||||
it != m_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * var = it->m_key;
|
||||
app * val = to_app(it->m_value);
|
||||
SASSERT(m_fpa_util.is_float(var->get_range()));
|
||||
SASSERT(var->get_range()->get_num_parameters() == 2);
|
||||
unsigned ebits = m_fpa_util.get_ebits(var->get_range());
|
||||
unsigned sbits = m_fpa_util.get_sbits(var->get_range());
|
||||
|
||||
app * a0 = to_app(val->get_arg(0));
|
||||
app * a1 = to_app(val->get_arg(1));
|
||||
app * a2 = to_app(val->get_arg(2));
|
||||
|
||||
expr_ref v0(m), v1(m), v2(m);
|
||||
#ifdef Z3DEBUG
|
||||
v0 = mc->get_const_interp(a0->get_decl());
|
||||
v1 = mc->get_const_interp(a1->get_decl());
|
||||
v2 = mc->get_const_interp(a2->get_decl());
|
||||
#else
|
||||
expr * bv = mc->get_const_interp(to_app(to_app(a0)->get_arg(0))->get_decl());
|
||||
unsigned bv_sz = m_bv_util.get_bv_size(bv);
|
||||
v0 = m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv);
|
||||
v1 = m_bv_util.mk_extract(bv_sz-2, sbits-1, bv);
|
||||
v2 = m_bv_util.mk_extract(sbits-2, 0, bv);
|
||||
#endif
|
||||
|
||||
if (!v0) v0 = m_bv_util.mk_numeral(0, 1);
|
||||
if (!v1) v1 = m_bv_util.mk_numeral(0, ebits);
|
||||
if (!v2) v2 = m_bv_util.mk_numeral(0, sbits-1);
|
||||
|
||||
expr_ref sgn(m), exp(m), sig(m);
|
||||
m_th_rw(v0, sgn);
|
||||
m_th_rw(v1, exp);
|
||||
m_th_rw(v2, sig);
|
||||
|
||||
SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP));
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0);
|
||||
SASSERT(to_app(val->get_arg(1))->get_decl()->get_arity() == 0);
|
||||
SASSERT(to_app(val->get_arg(2))->get_decl()->get_arity() == 0);
|
||||
seen.insert(to_app(val->get_arg(0))->get_decl());
|
||||
seen.insert(to_app(val->get_arg(1))->get_decl());
|
||||
seen.insert(to_app(val->get_arg(2))->get_decl());
|
||||
#else
|
||||
SASSERT(a->get_arg(0)->get_kind() == OP_EXTRACT);
|
||||
SASSERT(to_app(a->get_arg(0))->get_arg(0)->get_kind() == OP_EXTRACT);
|
||||
seen.insert(to_app(to_app(val->get_arg(0))->get_arg(0))->get_decl());
|
||||
#endif
|
||||
|
||||
if (!sgn && !sig && !exp)
|
||||
continue;
|
||||
|
||||
expr_ref cv(m);
|
||||
cv = convert_bv2fp(var->get_range(), sgn, exp, sig);
|
||||
target_model->register_decl(var, cv);
|
||||
|
||||
TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;);
|
||||
}
|
||||
}
|
||||
|
||||
void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
|
||||
it != m_rm_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * var = it->m_key;
|
||||
SASSERT(m_fpa_util.is_rm(var->get_range()));
|
||||
expr * val = it->m_value;
|
||||
SASSERT(m_fpa_util.is_bv2rm(val));
|
||||
expr * bvval = to_app(val)->get_arg(0);
|
||||
expr_ref fv(m);
|
||||
fv = convert_bv2rm(mc, to_app(bvval));
|
||||
TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;);
|
||||
target_model->register_decl(var, fv);
|
||||
seen.insert(to_app(bvval)->get_decl());
|
||||
}
|
||||
}
|
||||
|
||||
void bv2fpa_converter::convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
func_decl * f = it->m_key;
|
||||
app * pn_cnst = it->m_value.first;
|
||||
app * np_cnst = it->m_value.second;
|
||||
|
||||
expr_ref pzero(m), nzero(m);
|
||||
pzero = m_fpa_util.mk_pzero(f->get_range());
|
||||
nzero = m_fpa_util.mk_nzero(f->get_range());
|
||||
|
||||
expr_ref pn(m), np(m);
|
||||
if (!mc->eval(pn_cnst->get_decl(), pn)) pn = pzero;
|
||||
if (!mc->eval(np_cnst->get_decl(), np)) np = pzero;
|
||||
seen.insert(pn_cnst->get_decl());
|
||||
seen.insert(np_cnst->get_decl());
|
||||
|
||||
rational pn_num, np_num;
|
||||
unsigned bv_sz;
|
||||
m_bv_util.is_numeral(pn, pn_num, bv_sz);
|
||||
m_bv_util.is_numeral(np, np_num, bv_sz);
|
||||
|
||||
func_interp * flt_fi = alloc(func_interp, m, f->get_arity());
|
||||
expr * pn_args[2] = { pzero, nzero };
|
||||
if (pn != np) flt_fi->insert_new_entry(pn_args, (pn_num.is_one() ? nzero : pzero));
|
||||
flt_fi->set_else(np_num.is_one() ? nzero : pzero);
|
||||
|
||||
target_model->register_decl(f, flt_fi);
|
||||
TRACE("bv2fpa", tout << "fp.min/fp.max special: " << std::endl <<
|
||||
mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;);
|
||||
}
|
||||
}
|
||||
|
||||
void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
|
||||
it != m_uf2bvuf.end();
|
||||
it++) {
|
||||
seen.insert(it->m_value);
|
||||
|
||||
func_decl * f = it->m_key;
|
||||
if (f->get_arity() == 0)
|
||||
{
|
||||
array_util au(m);
|
||||
if (au.is_array(f->get_range())) {
|
||||
array_model am = convert_array_func_interp(mc, f, it->m_value);
|
||||
if (am.new_float_fd) target_model->register_decl(am.new_float_fd, am.new_float_fi);
|
||||
if (am.result) target_model->register_decl(f, am.result);
|
||||
if (am.bv_fd) seen.insert(am.bv_fd);
|
||||
}
|
||||
else {
|
||||
// Just keep.
|
||||
SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range()));
|
||||
expr_ref var(m), val(m);
|
||||
if (mc->eval(it->m_value, val))
|
||||
target_model->register_decl(f, val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
func_interp * fmv = convert_func_interp(mc, f, it->m_value);
|
||||
if (fmv) target_model->register_decl(f, fmv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bv2fpa_converter::display(std::ostream & out) {
|
||||
out << "(fpa2bv-model-converter";
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
|
||||
it != m_const2bv.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
|
||||
}
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
|
||||
it != m_rm_const2bv.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
|
||||
}
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
|
||||
it != m_uf2bvuf.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
|
||||
}
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " <<
|
||||
mk_ismt2_pp(it->m_value.second, m, indent) << ")";
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
|
||||
bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) {
|
||||
bv2fpa_converter * res = alloc(bv2fpa_converter, translator.to());
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
|
||||
it != m_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * k = translator(it->m_key);
|
||||
expr * v = translator(it->m_value);
|
||||
res->m_const2bv.insert(k, v);
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v);
|
||||
}
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
|
||||
it != m_rm_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * k = translator(it->m_key);
|
||||
expr * v = translator(it->m_value);
|
||||
res->m_rm_const2bv.insert(k, v);
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v);
|
||||
}
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
|
||||
it != m_uf2bvuf.end();
|
||||
it++) {
|
||||
func_decl * k = translator(it->m_key);
|
||||
func_decl * v = translator(it->m_value);
|
||||
res->m_uf2bvuf.insert(k, v);
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v);
|
||||
}
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
func_decl * k = translator(it->m_key);
|
||||
app * v1 = translator(it->m_value.first);
|
||||
app * v2 = translator(it->m_value.second);
|
||||
res->m_specials.insert(k, std::pair<app*, app*>(v1, v2));
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v1);
|
||||
translator.to().inc_ref(v2);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void bv2fpa_converter::convert(model_core * mc, model_core * float_mdl) {
|
||||
TRACE("bv2fpa", tout << "BV Model: " << std::endl;
|
||||
for (unsigned i = 0; i < mc->get_num_constants(); i++)
|
||||
tout << mc->get_constant(i)->get_name() << " --> " <<
|
||||
mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl;
|
||||
for (unsigned i = 0; i < mc->get_num_functions(); i++) {
|
||||
func_decl * f = mc->get_function(i);
|
||||
tout << f->get_name() << "(...) := " << std::endl;
|
||||
func_interp * fi = mc->get_func_interp(f);
|
||||
for (unsigned j = 0; j < fi->num_entries(); j++) {
|
||||
func_entry const * fe = fi->get_entry(j);
|
||||
for (unsigned k = 0; k < f->get_arity(); k++) {
|
||||
tout << mk_ismt2_pp(fe->get_arg(k), m) << " ";
|
||||
}
|
||||
tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl;
|
||||
}
|
||||
tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl;
|
||||
});
|
||||
|
||||
}
|
74
src/ast/fpa/bv2fpa_converter.h
Normal file
74
src/ast/fpa/bv2fpa_converter.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*++
|
||||
Copyright (c) 2016 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv2fpa_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Model conversion for fpa2bv_converter
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2016-10-15
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef BV2FPA_CONVERTER_H_
|
||||
#define BV2FPA_CONVERTER_H_
|
||||
|
||||
#include"fpa_decl_plugin.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"th_rewriter.h"
|
||||
#include"model_core.h"
|
||||
#include"fpa2bv_converter.h"
|
||||
|
||||
|
||||
class bv2fpa_converter {
|
||||
ast_manager & m;
|
||||
fpa_util m_fpa_util;
|
||||
bv_util m_bv_util;
|
||||
th_rewriter m_th_rw;
|
||||
|
||||
obj_map<func_decl, expr*> m_const2bv;
|
||||
obj_map<func_decl, expr*> m_rm_const2bv;
|
||||
obj_map<func_decl, func_decl*> m_uf2bvuf;
|
||||
obj_map<func_decl, std::pair<app*, app*> > m_specials;
|
||||
|
||||
public:
|
||||
bv2fpa_converter(ast_manager & m);
|
||||
bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv);
|
||||
virtual ~bv2fpa_converter();
|
||||
|
||||
void display(std::ostream & out);
|
||||
bv2fpa_converter * translate(ast_translation & translator);
|
||||
|
||||
expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig);
|
||||
expr_ref convert_bv2fp(model_core * mc, sort * s, app * bv);
|
||||
expr_ref convert_bv2rm(expr * eval_v);
|
||||
expr_ref convert_bv2rm(model_core * mc, app * val);
|
||||
|
||||
void convert(model_core * mc, model_core * float_mdl);
|
||||
void convert_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
|
||||
void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
|
||||
void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
|
||||
void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
|
||||
|
||||
func_interp * convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f);
|
||||
expr_ref rebuild_floats(model_core * mc, sort * s, app * e);
|
||||
|
||||
class array_model {
|
||||
public:
|
||||
func_decl * new_float_fd;
|
||||
func_interp * new_float_fi;
|
||||
func_decl * bv_fd;
|
||||
expr_ref result;
|
||||
array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {}
|
||||
};
|
||||
|
||||
array_model convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -23,6 +23,7 @@ Notes:
|
|||
#include"th_rewriter.h"
|
||||
|
||||
#include"fpa2bv_converter.h"
|
||||
#include"fpa_rewriter.h"
|
||||
|
||||
#define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); }
|
||||
|
||||
|
@ -32,7 +33,6 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) :
|
|||
m_util(m),
|
||||
m_bv_util(m),
|
||||
m_arith_util(m),
|
||||
m_array_util(m),
|
||||
m_dt_util(m),
|
||||
m_seq_util(m),
|
||||
m_mpf_manager(m_util.fm()),
|
||||
|
@ -165,7 +165,6 @@ void fpa2bv_converter::mk_numeral(sort * s, mpf const & v, expr_ref & result) {
|
|||
result = m_util.mk_fp(bv_sgn, biased_exp, bv_sig);
|
||||
TRACE("fpa2bv_dbg", tout << "value of [" << sign << " " << m_mpz_manager.to_string(sig) << " " << exp << "] is "
|
||||
<< mk_ismt2_pp(result, m) << std::endl;);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2772,6 +2771,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar
|
|||
|
||||
expr_ref unspec(m);
|
||||
unspec = mk_to_real_unspecified(ebits, sbits);
|
||||
|
||||
result = m.mk_ite(x_is_zero, zero, res);
|
||||
result = m.mk_ite(x_is_inf, unspec, result);
|
||||
result = m.mk_ite(x_is_nan, unspec, result);
|
||||
|
@ -3073,13 +3073,55 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const *
|
|||
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
|
||||
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
|
||||
m_bv_util.mk_numeral(1, 1))));
|
||||
else
|
||||
nanv = mk_to_ieee_bv_unspecified(ebits, sbits);
|
||||
else {
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits);
|
||||
mk_to_ieee_bv_unspecified(unspec->get_decl(), 0, 0, nanv);
|
||||
}
|
||||
|
||||
expr_ref sgn_e_s(m);
|
||||
sgn_e_s = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s);
|
||||
m_simp.mk_ite(x_is_nan, nanv, sgn_e_s, result);
|
||||
|
||||
TRACE("fpa2bv_to_ieee_bv", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 0);
|
||||
unsigned ebits = f->get_parameter(0).get_int();
|
||||
unsigned sbits = f->get_parameter(1).get_int();
|
||||
|
||||
if (m_hi_fp_unspecified) {
|
||||
result = m_bv_util.mk_concat(m_bv_util.mk_concat(
|
||||
m_bv_util.mk_numeral(0, 1),
|
||||
m_bv_util.mk_numeral(-1, ebits)),
|
||||
m_bv_util.mk_numeral(1, sbits-1));
|
||||
}
|
||||
else {
|
||||
func_decl * fd;
|
||||
if (m_uf2bvuf.find(f, fd))
|
||||
result = m.mk_const(fd);
|
||||
else {
|
||||
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
|
||||
m_uf2bvuf.insert(f, fd);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(fd);
|
||||
result = m.mk_const(fd);
|
||||
|
||||
expr_ref exp_bv(m), exp_all_ones(m);
|
||||
exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result);
|
||||
exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits));
|
||||
m_extra_assertions.push_back(exp_all_ones);
|
||||
|
||||
expr_ref sig_bv(m), sig_is_non_zero(m);
|
||||
sig_bv = m_bv_util.mk_extract(sbits-2, 0, result);
|
||||
sig_is_non_zero = m.mk_not(m.mk_eq(sig_bv, m_bv_util.mk_numeral(0, sbits-1)));
|
||||
m_extra_assertions.push_back(sig_is_non_zero);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("fpa2bv_to_ieee_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
}
|
||||
|
||||
|
@ -3112,11 +3154,14 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
|
|||
|
||||
// NaN, Inf, or negative (except -0) -> unspecified
|
||||
expr_ref c1(m), v1(m);
|
||||
if (!is_signed)
|
||||
if (!is_signed) {
|
||||
c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero)));
|
||||
else
|
||||
v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
|
||||
}
|
||||
else {
|
||||
c1 = m.mk_or(x_is_nan, x_is_inf);
|
||||
v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
|
||||
v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz);
|
||||
}
|
||||
dbg_decouple("fpa2bv_to_bv_c1", c1);
|
||||
|
||||
// +-Zero -> 0
|
||||
|
@ -3226,7 +3271,8 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
|
|||
dbg_decouple("fpa2bv_to_bv_rnd", rnd);
|
||||
|
||||
expr_ref unspec(m);
|
||||
unspec = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
|
||||
unspec = is_signed ? mk_to_sbv_unspecified(ebits, sbits, bv_sz) :
|
||||
mk_to_ubv_unspecified(ebits, sbits, bv_sz);
|
||||
result = m.mk_ite(rnd_has_overflown, unspec, rnd);
|
||||
result = m.mk_ite(c_in_limits, result, unspec);
|
||||
result = m.mk_ite(c2, v2, result);
|
||||
|
@ -3247,101 +3293,85 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg
|
|||
mk_to_bv(f, num, args, true, result);
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
|
||||
expr_ref result(m);
|
||||
void fpa2bv_converter::mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 0);
|
||||
unsigned width = m_bv_util.get_bv_size(f->get_range());
|
||||
|
||||
if (m_hi_fp_unspecified)
|
||||
result = m_bv_util.mk_numeral(0, width);
|
||||
else {
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
if (!m_uf2bvuf.find(f, fd)) {
|
||||
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
|
||||
m_uf2bvuf.insert(f, fd);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
}
|
||||
return result;
|
||||
|
||||
TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
|
||||
expr_ref res(m);
|
||||
app_ref u(m);
|
||||
u = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
|
||||
mk_to_sbv_unspecified(u->get_decl(), 0, 0, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 0);
|
||||
unsigned width = m_bv_util.get_bv_size(f->get_range());
|
||||
|
||||
if (m_hi_fp_unspecified)
|
||||
result = m_bv_util.mk_numeral(0, width);
|
||||
else {
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(f, fd)) {
|
||||
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
|
||||
m_uf2bvuf.insert(f, fd);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
}
|
||||
|
||||
TRACE("fpa2bv_to_sbv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
|
||||
expr_ref result(m);
|
||||
if (m_hi_fp_unspecified)
|
||||
result = m_bv_util.mk_numeral(0, width);
|
||||
else {
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
}
|
||||
return result;
|
||||
expr_ref res(m);
|
||||
app_ref u(m);
|
||||
u = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
|
||||
mk_to_sbv_unspecified(u->get_decl(), 0, 0, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) {
|
||||
expr_ref result(m);
|
||||
void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
if (m_hi_fp_unspecified)
|
||||
result = m_arith_util.mk_numeral(rational(0), false);
|
||||
else {
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_real_unspecified(ebits, sbits);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
if (!m_uf2bvuf.find(f, fd)) {
|
||||
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
|
||||
m_uf2bvuf.insert(f, fd);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
result = unspec;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) {
|
||||
expr_ref result(m);
|
||||
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
|
||||
app_ref mask(m), extra(m), result_and_mask(m);
|
||||
mask = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
|
||||
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
|
||||
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
|
||||
m_bv_util.mk_numeral(1, 1))));
|
||||
expr * args[2] = { result, mask };
|
||||
result_and_mask = m.mk_app(m_bv_util.get_fid(), OP_BAND, 2, args);
|
||||
extra = m.mk_eq(result_and_mask, mask);
|
||||
m_extra_assertions.push_back(extra);
|
||||
|
||||
return result;
|
||||
expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) {
|
||||
expr_ref res(m);
|
||||
app_ref u(m);
|
||||
u = m_util.mk_internal_to_real_unspecified(ebits, sbits);
|
||||
mk_to_real_unspecified(u->get_decl(), 0, 0, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
|
|
|
@ -43,7 +43,6 @@ protected:
|
|||
fpa_util m_util;
|
||||
bv_util m_bv_util;
|
||||
arith_util m_arith_util;
|
||||
array_util m_array_util;
|
||||
datatype_util m_dt_util;
|
||||
seq_util m_seq_util;
|
||||
mpf_manager & m_mpf_manager;
|
||||
|
@ -57,6 +56,7 @@ protected:
|
|||
special_t m_min_max_specials;
|
||||
|
||||
friend class fpa2bv_model_converter;
|
||||
friend class bv2fpa_converter;
|
||||
|
||||
public:
|
||||
fpa2bv_converter(ast_manager & m);
|
||||
|
@ -71,9 +71,9 @@ public:
|
|||
bool is_rm(expr * e) { return is_app(e) && m_util.is_rm(e); }
|
||||
bool is_rm(sort * s) { return m_util.is_rm(s); }
|
||||
bool is_float_family(func_decl * f) { return f->get_family_id() == m_util.get_family_id(); }
|
||||
|
||||
|
||||
void mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
|
||||
void split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const;
|
||||
void split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const;
|
||||
|
||||
|
@ -133,12 +133,16 @@ public:
|
|||
void mk_to_fp_signed(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_fp_unsigned(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result);
|
||||
void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
void mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; }
|
||||
|
||||
|
@ -149,16 +153,11 @@ public:
|
|||
void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits);
|
||||
expr_ref mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
|
||||
|
||||
void reset(void);
|
||||
|
||||
void dbg_decouple(const char * prefix, expr_ref & e);
|
||||
expr_ref_vector m_extra_assertions;
|
||||
|
||||
|
||||
special_t const & get_min_max_specials() const { return m_min_max_specials; };
|
||||
const2bv_t const & get_const2bv() const { return m_const2bv; };
|
||||
const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; };
|
||||
|
@ -227,6 +226,10 @@ private:
|
|||
void mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result);
|
||||
|
||||
void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result);
|
||||
|
||||
expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -143,9 +143,13 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: m_conv.mk_to_ubv_unspecified(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: m_conv.mk_to_sbv_unspecified(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: m_conv.mk_to_real_unspecified(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: m_conv.mk_to_ieee_bv_unspecified(f, num, args, result); return BR_DONE;
|
||||
|
||||
case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL;
|
||||
case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL;
|
||||
|
@ -157,12 +161,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
|
||||
case OP_FPA_INTERNAL_BVWRAP:
|
||||
case OP_FPA_INTERNAL_BV2RM:
|
||||
|
||||
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
|
||||
return BR_FAILED;
|
||||
|
||||
default:
|
||||
TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
|
||||
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
|
||||
|
|
|
@ -665,14 +665,14 @@ func_decl * fpa_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, pa
|
|||
func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 1)
|
||||
m_manager->raise_exception("invalid number of arguments to to_ieee_bv");
|
||||
m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv");
|
||||
if (!is_float_sort(domain[0]))
|
||||
m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
|
||||
|
||||
unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int();
|
||||
parameter ps[] = { parameter(float_sz) };
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(BV_SORT, 1, ps);
|
||||
symbol name("to_ieee_bv");
|
||||
symbol name("fp.to_ieee_bv");
|
||||
return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k));
|
||||
}
|
||||
|
||||
|
@ -758,15 +758,15 @@ func_decl * fpa_decl_plugin::mk_internal_to_ieee_bv_unspecified(
|
|||
decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 0)
|
||||
m_manager->raise_exception("invalid number of arguments to to_ieee_bv_unspecified; expecting none");
|
||||
m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv_unspecified; expecting none");
|
||||
if (num_parameters != 2)
|
||||
m_manager->raise_exception("invalid number of parameters to to_ieee_bv_unspecified; expecting 2");
|
||||
m_manager->raise_exception("invalid number of parameters to fp.to_ieee_bv_unspecified; expecting 2");
|
||||
if (!parameters[0].is_int() || !parameters[1].is_int())
|
||||
m_manager->raise_exception("invalid parameters type provided to to_ieee_bv_unspecified; expecting 2 integers");
|
||||
m_manager->raise_exception("invalid parameters type provided to fp.to_ieee_bv_unspecified; expecting 2 integers");
|
||||
|
||||
parameter width_p[1] = { parameter(parameters[0].get_int() + parameters[1].get_int()) };
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, width_p);
|
||||
return m_manager->mk_func_decl(symbol("to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
return m_manager->mk_func_decl(symbol("fp.to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
|
||||
|
||||
|
@ -915,7 +915,8 @@ void fpa_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol cons
|
|||
op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED));
|
||||
|
||||
/* Extensions */
|
||||
op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV));
|
||||
op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV));
|
||||
op_names.push_back(builtin_name("fp.to_ieee_bv", OP_FPA_TO_IEEE_BV));
|
||||
}
|
||||
|
||||
void fpa_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
|
||||
|
|
|
@ -259,7 +259,7 @@ public:
|
|||
bool is_rm(sort * s) const { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); }
|
||||
bool is_float(expr * e) const { return is_float(m_manager.get_sort(e)); }
|
||||
bool is_rm(expr * e) const { return is_rm(m_manager.get_sort(e)); }
|
||||
bool is_fp(expr * e) const { return is_app_of(e, m_fid, OP_FPA_FP); }
|
||||
bool is_fp(expr * e) const { return is_app_of(e, m_fid, OP_FPA_FP); }
|
||||
unsigned get_ebits(sort * s) const;
|
||||
unsigned get_sbits(sort * s) const;
|
||||
|
||||
|
@ -294,13 +294,13 @@ public:
|
|||
bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pzero(v); }
|
||||
bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nzero(v); }
|
||||
|
||||
app * mk_fp(expr * sgn, expr * exp, expr * sig) {
|
||||
app * mk_fp(expr * sgn, expr * exp, expr * sig) {
|
||||
SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1);
|
||||
SASSERT(m_bv_util.is_bv(exp));
|
||||
SASSERT(m_bv_util.is_bv(sig));
|
||||
return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig);
|
||||
SASSERT(m_bv_util.is_bv(sig));
|
||||
return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig);
|
||||
}
|
||||
|
||||
|
||||
app * mk_to_fp(sort * s, expr * bv_t) {
|
||||
SASSERT(is_float(s) && s->get_num_parameters() == 2);
|
||||
return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t);
|
||||
|
@ -377,28 +377,28 @@ public:
|
|||
app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
|
||||
app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits);
|
||||
|
||||
bool is_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); }
|
||||
bool is_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; }
|
||||
bool is_bv2rm(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); }
|
||||
bool is_bv2rm(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; }
|
||||
bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); }
|
||||
bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; }
|
||||
bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); }
|
||||
bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; }
|
||||
|
||||
bool is_min_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); }
|
||||
bool is_min_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); }
|
||||
bool is_max_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); }
|
||||
bool is_max_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); }
|
||||
bool is_to_ubv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); }
|
||||
bool is_to_sbv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); }
|
||||
bool is_to_ieee_bv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); }
|
||||
bool is_to_real_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); }
|
||||
bool is_min_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); }
|
||||
bool is_min_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); }
|
||||
bool is_max_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); }
|
||||
bool is_max_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); }
|
||||
bool is_to_ubv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); }
|
||||
bool is_to_sbv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); }
|
||||
bool is_to_ieee_bv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); }
|
||||
bool is_to_real_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); }
|
||||
|
||||
bool is_min_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; }
|
||||
bool is_min_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; }
|
||||
bool is_max_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; }
|
||||
bool is_max_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; }
|
||||
bool is_to_ubv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; }
|
||||
bool is_to_sbv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; }
|
||||
bool is_to_ieee_bv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; }
|
||||
bool is_to_real_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; }
|
||||
bool is_min_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; }
|
||||
bool is_min_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; }
|
||||
bool is_max_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; }
|
||||
bool is_max_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; }
|
||||
bool is_to_ubv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; }
|
||||
bool is_to_sbv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; }
|
||||
bool is_to_ieee_bv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; }
|
||||
bool is_to_real_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; }
|
||||
|
||||
bool contains_floats(ast * a);
|
||||
};
|
||||
|
|
|
@ -101,35 +101,47 @@ void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const
|
|||
}
|
||||
|
||||
void pb_util::normalize(unsigned num_args, rational const* coeffs, rational const& k) {
|
||||
rational d(1);
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
d = lcm(d, denominator(coeffs[i]));
|
||||
}
|
||||
m_coeffs.reset();
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
m_coeffs.push_back(d*coeffs[i]);
|
||||
bool all_ones = true;
|
||||
for (unsigned i = 0; i < num_args && all_ones; ++i) {
|
||||
all_ones = denominator(coeffs[i]).is_one();
|
||||
}
|
||||
if (all_ones) {
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
m_coeffs.push_back(coeffs[i]);
|
||||
}
|
||||
m_k = k;
|
||||
}
|
||||
else {
|
||||
rational d(1);
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
d = lcm(d, denominator(coeffs[i]));
|
||||
}
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
m_coeffs.push_back(d*coeffs[i]);
|
||||
}
|
||||
m_k = d*k;
|
||||
}
|
||||
m_k = d*k;
|
||||
}
|
||||
|
||||
app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
|
||||
normalize(num_args, coeffs, k);
|
||||
vector<parameter> params;
|
||||
params.push_back(parameter(floor(m_k)));
|
||||
m_params.reset();
|
||||
m_params.push_back(parameter(floor(m_k)));
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
params.push_back(parameter(m_coeffs[i]));
|
||||
m_params.push_back(parameter(m_coeffs[i]));
|
||||
}
|
||||
return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||
return m.mk_app(m_fid, OP_PB_LE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||
}
|
||||
|
||||
app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
|
||||
normalize(num_args, coeffs, k);
|
||||
vector<parameter> params;
|
||||
params.push_back(parameter(ceil(m_k)));
|
||||
m_params.reset();
|
||||
m_params.push_back(parameter(ceil(m_k)));
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
params.push_back(parameter(m_coeffs[i]));
|
||||
m_params.push_back(parameter(m_coeffs[i]));
|
||||
}
|
||||
return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||
return m.mk_app(m_fid, OP_PB_GE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||
}
|
||||
|
||||
app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
|
||||
|
@ -137,12 +149,12 @@ app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const *
|
|||
if (!m_k.is_int()) {
|
||||
return m.mk_false();
|
||||
}
|
||||
vector<parameter> params;
|
||||
params.push_back(parameter(m_k));
|
||||
m_params.reset();
|
||||
m_params.push_back(parameter(m_k));
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
params.push_back(parameter(m_coeffs[i]));
|
||||
m_params.push_back(parameter(m_coeffs[i]));
|
||||
}
|
||||
return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||
return m.mk_app(m_fid, OP_PB_EQ, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||
}
|
||||
|
||||
// ax + by < k
|
||||
|
|
|
@ -80,6 +80,7 @@ class pb_util {
|
|||
ast_manager & m;
|
||||
family_id m_fid;
|
||||
vector<rational> m_coeffs;
|
||||
vector<parameter> m_params;
|
||||
rational m_k;
|
||||
void normalize(unsigned num_args, rational const* coeffs, rational const& k);
|
||||
public:
|
||||
|
|
292
src/ast/rewriter/fd_rewriter.cpp
Normal file
292
src/ast/rewriter/fd_rewriter.cpp
Normal file
|
@ -0,0 +1,292 @@
|
|||
/*++
|
||||
Copyright (c) 2016 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fd_rewriter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Conversion from enumeration types to bit-vectors.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2016-10-18
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
#include"rewriter.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"fd_rewriter.h"
|
||||
#include"ast_util.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
struct fd_rewriter::imp {
|
||||
ast_manager& m;
|
||||
params_ref m_params;
|
||||
obj_map<func_decl, func_decl*> m_enum2bv;
|
||||
obj_map<func_decl, func_decl*> m_bv2enum;
|
||||
obj_map<func_decl, expr*> m_enum2def;
|
||||
expr_ref_vector m_bounds;
|
||||
datatype_util m_dt;
|
||||
func_decl_ref_vector m_enum_consts;
|
||||
func_decl_ref_vector m_enum_bvs;
|
||||
expr_ref_vector m_enum_defs;
|
||||
unsigned_vector m_enum_consts_lim;
|
||||
unsigned m_num_translated;
|
||||
i_sort_pred* m_sort_pred;
|
||||
|
||||
struct rw_cfg : public default_rewriter_cfg {
|
||||
imp& m_imp;
|
||||
ast_manager& m;
|
||||
datatype_util m_dt;
|
||||
bv_util m_bv;
|
||||
|
||||
rw_cfg(imp& i, ast_manager & m) :
|
||||
m_imp(i),
|
||||
m(m),
|
||||
m_dt(m),
|
||||
m_bv(m)
|
||||
{}
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
expr_ref a0(m), a1(m);
|
||||
expr_ref_vector _args(m);
|
||||
if (m.is_eq(f) && reduce_arg(args[0], a0) && reduce_arg(args[1], a1)) {
|
||||
result = m.mk_eq(a0, a1);
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (m.is_distinct(f) && reduce_args(num, args, _args)) {
|
||||
result = m.mk_distinct(_args.size(), _args.c_ptr());
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) {
|
||||
unsigned idx = m_dt.get_recognizer_constructor_idx(f);
|
||||
a1 = m_bv.mk_numeral(rational(idx), get_sort(a0));
|
||||
result = m.mk_eq(a0, a1);
|
||||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
check_for_fd(num, args);
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
bool reduce_args(unsigned sz, expr*const* as, expr_ref_vector& result) {
|
||||
expr_ref tmp(m);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
if (!reduce_arg(as[i], tmp)) return false;
|
||||
result.push_back(tmp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void throw_non_fd(expr* e) {
|
||||
std::stringstream strm;
|
||||
strm << "unabled nested data-type expression " << mk_pp(e, m);
|
||||
throw rewriter_exception(strm.str().c_str());
|
||||
}
|
||||
|
||||
void check_for_fd(unsigned n, expr* const* args) {
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
if (m_imp.is_fd(get_sort(args[i]))) {
|
||||
throw_non_fd(args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool reduce_arg(expr* a, expr_ref& result) {
|
||||
|
||||
sort* s = get_sort(a);
|
||||
if (!m_imp.is_fd(s)) {
|
||||
return false;
|
||||
}
|
||||
unsigned bv_size = get_bv_size(s);
|
||||
|
||||
if (is_var(a)) {
|
||||
result = m.mk_var(to_var(a)->get_idx(), m_bv.mk_sort(bv_size));
|
||||
return true;
|
||||
}
|
||||
SASSERT(is_app(a));
|
||||
func_decl* f = to_app(a)->get_decl();
|
||||
if (m_dt.is_constructor(f)) {
|
||||
unsigned idx = m_dt.get_constructor_idx(f);
|
||||
result = m_bv.mk_numeral(idx, bv_size);
|
||||
}
|
||||
else if (is_uninterp_const(a)) {
|
||||
func_decl* f_fresh;
|
||||
if (m_imp.m_enum2bv.find(f, f_fresh)) {
|
||||
result = m.mk_const(f_fresh);
|
||||
return true;
|
||||
}
|
||||
|
||||
// create a fresh variable, add bounds constraints for it.
|
||||
unsigned nc = m_dt.get_datatype_num_constructors(s);
|
||||
result = m.mk_fresh_const(f->get_name().str().c_str(), m_bv.mk_sort(bv_size));
|
||||
f_fresh = to_app(result)->get_decl();
|
||||
if (!is_power_of_two(nc)) {
|
||||
m_imp.m_bounds.push_back(m_bv.mk_ule(result, m_bv.mk_numeral(nc-1, bv_size)));
|
||||
}
|
||||
expr_ref f_def(m);
|
||||
ptr_vector<func_decl> const& cs = *m_dt.get_datatype_constructors(s);
|
||||
f_def = m.mk_const(cs[nc-1]);
|
||||
for (unsigned i = nc - 1; i > 0; ) {
|
||||
--i;
|
||||
f_def = m.mk_ite(m.mk_eq(result, m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def);
|
||||
}
|
||||
m_imp.m_enum2def.insert(f, f_def);
|
||||
m_imp.m_enum2bv.insert(f, f_fresh);
|
||||
m_imp.m_bv2enum.insert(f_fresh, f);
|
||||
m_imp.m_enum_consts.push_back(f);
|
||||
m_imp.m_enum_bvs.push_back(f_fresh);
|
||||
m_imp.m_enum_defs.push_back(f_def);
|
||||
}
|
||||
else {
|
||||
throw_non_fd(a);
|
||||
}
|
||||
++m_imp.m_num_translated;
|
||||
return true;
|
||||
}
|
||||
|
||||
ptr_buffer<sort> m_sorts;
|
||||
|
||||
bool reduce_quantifier(
|
||||
quantifier * q,
|
||||
expr * old_body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
m_sorts.reset();
|
||||
expr_ref_vector bounds(m);
|
||||
bool found = false;
|
||||
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
|
||||
sort* s = q->get_decl_sort(i);
|
||||
if (m_imp.is_fd(s)) {
|
||||
unsigned bv_size = get_bv_size(s);
|
||||
m_sorts.push_back(m_bv.mk_sort(bv_size));
|
||||
unsigned nc = m_dt.get_datatype_num_constructors(s);
|
||||
if (!is_power_of_two(nc)) {
|
||||
bounds.push_back(m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_bv.mk_numeral(nc-1, bv_size)));
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
else {
|
||||
m_sorts.push_back(s);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
expr_ref new_body_ref(old_body, m), tmp(m);
|
||||
if (!bounds.empty()) {
|
||||
if (q->is_forall()) {
|
||||
new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref);
|
||||
}
|
||||
else {
|
||||
bounds.push_back(new_body_ref);
|
||||
new_body_ref = mk_and(bounds);
|
||||
}
|
||||
}
|
||||
result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref,
|
||||
q->get_weight(), q->get_qid(), q->get_skid(),
|
||||
q->get_num_patterns(), new_patterns,
|
||||
q->get_num_no_patterns(), new_no_patterns);
|
||||
result_pr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned get_bv_size(sort* s) {
|
||||
unsigned nc = m_dt.get_datatype_num_constructors(s);
|
||||
unsigned bv_size = 1;
|
||||
while ((unsigned)(1 << bv_size) < nc) {
|
||||
++bv_size;
|
||||
}
|
||||
return bv_size;
|
||||
}
|
||||
};
|
||||
|
||||
struct rw : public rewriter_tpl<rw_cfg> {
|
||||
rw_cfg m_cfg;
|
||||
|
||||
rw(imp& t, ast_manager & m, params_ref const & p) :
|
||||
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(t, m) {
|
||||
}
|
||||
};
|
||||
|
||||
rw m_rw;
|
||||
|
||||
imp(ast_manager& m, params_ref const& p):
|
||||
m(m), m_params(p), m_bounds(m),
|
||||
m_dt(m),
|
||||
m_enum_consts(m),
|
||||
m_enum_bvs(m),
|
||||
m_enum_defs(m),
|
||||
m_num_translated(0),
|
||||
m_sort_pred(0),
|
||||
m_rw(*this, m, p) {
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {}
|
||||
unsigned get_num_steps() const { return m_rw.get_num_steps(); }
|
||||
void cleanup() { m_rw.cleanup(); }
|
||||
void operator()(expr * e, expr_ref & result, proof_ref & result_proof) {
|
||||
m_rw(e, result, result_proof);
|
||||
}
|
||||
void push() {
|
||||
m_enum_consts_lim.push_back(m_enum_consts.size());
|
||||
}
|
||||
void pop(unsigned num_scopes) {
|
||||
SASSERT(m_bounds.empty()); // bounds must be flushed before pop.
|
||||
if (num_scopes > 0) {
|
||||
SASSERT(num_scopes <= m_enum_consts_lim.size());
|
||||
unsigned new_sz = m_enum_consts_lim.size() - num_scopes;
|
||||
unsigned lim = m_enum_consts_lim[new_sz];
|
||||
for (unsigned i = m_enum_consts.size(); i > lim; ) {
|
||||
--i;
|
||||
func_decl* f = m_enum_consts[i].get();
|
||||
func_decl* f_fresh = m_enum2bv.find(f);
|
||||
m_bv2enum.erase(f_fresh);
|
||||
m_enum2bv.erase(f);
|
||||
m_enum2def.erase(f);
|
||||
}
|
||||
m_enum_consts_lim.resize(new_sz);
|
||||
m_enum_consts.resize(lim);
|
||||
m_enum_defs.resize(lim);
|
||||
m_enum_bvs.resize(lim);
|
||||
}
|
||||
}
|
||||
|
||||
void flush_side_constraints(expr_ref_vector& side_constraints) {
|
||||
side_constraints.append(m_bounds);
|
||||
m_bounds.reset();
|
||||
}
|
||||
|
||||
bool is_fd(sort* s) {
|
||||
return m_dt.is_enum_sort(s) && (!m_sort_pred || (*m_sort_pred)(s));
|
||||
}
|
||||
|
||||
void set_is_fd(i_sort_pred* sp) {
|
||||
m_sort_pred = sp;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
fd_rewriter::fd_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); }
|
||||
fd_rewriter::~fd_rewriter() { dealloc(m_imp); }
|
||||
void fd_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); }
|
||||
ast_manager & fd_rewriter::m() const { return m_imp->m; }
|
||||
unsigned fd_rewriter::get_num_steps() const { return m_imp->get_num_steps(); }
|
||||
void fd_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); }
|
||||
obj_map<func_decl, func_decl*> const& fd_rewriter::enum2bv() const { return m_imp->m_enum2bv; }
|
||||
obj_map<func_decl, func_decl*> const& fd_rewriter::bv2enum() const { return m_imp->m_bv2enum; }
|
||||
obj_map<func_decl, expr*> const& fd_rewriter::enum2def() const { return m_imp->m_enum2def; }
|
||||
void fd_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); }
|
||||
void fd_rewriter::push() { m_imp->push(); }
|
||||
void fd_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); }
|
||||
void fd_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); }
|
||||
unsigned fd_rewriter::num_translated() const { return m_imp->m_num_translated; }
|
||||
void fd_rewriter::set_is_fd(i_sort_pred* sp) const { m_imp->set_is_fd(sp); }
|
48
src/ast/rewriter/fd_rewriter.h
Normal file
48
src/ast/rewriter/fd_rewriter.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*++
|
||||
Copyright (c) 2016 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fd_rewriter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Conversion from enumeration types to bit-vectors.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2016-10-18
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef ENUM_REWRITER_H_
|
||||
#define ENUM_REWRITER_H_
|
||||
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"expr_functors.h"
|
||||
|
||||
class fd_rewriter {
|
||||
struct imp;
|
||||
imp* m_imp;
|
||||
public:
|
||||
fd_rewriter(ast_manager & m, params_ref const& p);
|
||||
~fd_rewriter();
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
ast_manager & m() const;
|
||||
unsigned get_num_steps() const;
|
||||
void cleanup();
|
||||
obj_map<func_decl, func_decl*> const& enum2bv() const;
|
||||
obj_map<func_decl, func_decl*> const& bv2enum() const;
|
||||
obj_map<func_decl, expr*> const& enum2def() const;
|
||||
void operator()(expr * e, expr_ref & result, proof_ref & result_proof);
|
||||
void push();
|
||||
void pop(unsigned num_scopes);
|
||||
void flush_side_constraints(expr_ref_vector& side_constraints);
|
||||
unsigned num_translated() const;
|
||||
void set_is_fd(i_sort_pred* sp) const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -18,11 +18,12 @@ Notes:
|
|||
--*/
|
||||
#include"fpa_rewriter.h"
|
||||
#include"fpa_rewriter_params.hpp"
|
||||
#include"ast_smt2_pp.h"
|
||||
|
||||
fpa_rewriter::fpa_rewriter(ast_manager & m, params_ref const & p) :
|
||||
m_util(m),
|
||||
m_fm(m_util.fm()),
|
||||
m_hi_fp_unspecified(true) {
|
||||
m_hi_fp_unspecified(false) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
|
@ -98,7 +99,7 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_MAX_UNSPECIFIED:
|
||||
SASSERT(num_args == 2); st = BR_FAILED; break;
|
||||
|
||||
|
||||
case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break;
|
||||
case OP_FPA_INTERNAL_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break;
|
||||
|
||||
|
@ -117,34 +118,40 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
|
||||
br_status fpa_rewriter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
|
||||
bv_util bu(m());
|
||||
if (m_hi_fp_unspecified)
|
||||
if (m_hi_fp_unspecified) {
|
||||
// The "hardware interpretation" is 0.
|
||||
result = bu.mk_numeral(0, width);
|
||||
else
|
||||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
|
||||
|
||||
return BR_DONE;
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
|
||||
bv_util bu(m());
|
||||
if (m_hi_fp_unspecified)
|
||||
if (m_hi_fp_unspecified) {
|
||||
// The "hardware interpretation" is 0.
|
||||
result = bu.mk_numeral(0, width);
|
||||
else
|
||||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
|
||||
|
||||
return BR_DONE;
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) {
|
||||
if (m_hi_fp_unspecified)
|
||||
if (m_hi_fp_unspecified) {
|
||||
// The "hardware interpretation" is 0.
|
||||
result = m_util.au().mk_numeral(rational(0), false);
|
||||
else
|
||||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
result = m_util.mk_internal_to_real_unspecified(ebits, sbits);
|
||||
|
||||
return BR_DONE;
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
|
@ -776,10 +783,8 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
m_util.is_numeral(arg2, v)) {
|
||||
const mpf & x = v.get();
|
||||
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) {
|
||||
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v))
|
||||
return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
|
||||
bv_util bu(m());
|
||||
scoped_mpq q(m_fm.mpq_manager());
|
||||
|
@ -789,11 +794,13 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
rational ul, ll;
|
||||
ul = m_fm.m_powers2.m1(bv_sz);
|
||||
ll = rational(0);
|
||||
if (r >= ll && r <= ul)
|
||||
if (r >= ll && r <= ul) {
|
||||
result = bu.mk_numeral(r, bv_sz);
|
||||
return BR_DONE;
|
||||
}
|
||||
else
|
||||
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_DONE;
|
||||
return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
|
@ -810,10 +817,8 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
m_util.is_numeral(arg2, v)) {
|
||||
const mpf & x = v.get();
|
||||
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
|
||||
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v))
|
||||
return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
|
||||
bv_util bu(m());
|
||||
scoped_mpq q(m_fm.mpq_manager());
|
||||
|
@ -823,46 +828,42 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
rational ul, ll;
|
||||
ul = m_fm.m_powers2.m1(bv_sz - 1);
|
||||
ll = - m_fm.m_powers2(bv_sz - 1);
|
||||
if (r >= ll && r <= ul)
|
||||
if (r >= ll && r <= ul) {
|
||||
result = bu.mk_numeral(r, bv_sz);
|
||||
return BR_DONE;
|
||||
}
|
||||
else
|
||||
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_DONE;
|
||||
return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result) {
|
||||
TRACE("fp_rewriter", tout << "to_ieee_bv of " << mk_ismt2_pp(arg, m()) << std::endl;);
|
||||
scoped_mpf v(m_fm);
|
||||
|
||||
if (m_util.is_numeral(arg, v)) {
|
||||
TRACE("fp_rewriter", tout << "to_ieee_bv numeral: " << m_fm.to_string(v) << std::endl;);
|
||||
bv_util bu(m());
|
||||
const mpf & x = v.get();
|
||||
|
||||
if (m_fm.is_nan(v)) {
|
||||
if (m_hi_fp_unspecified) {
|
||||
result = bu.mk_concat(bu.mk_numeral(0, 1),
|
||||
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
|
||||
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
|
||||
bu.mk_numeral(1, 1))));
|
||||
expr * args[4] = { bu.mk_numeral(0, 1),
|
||||
bu.mk_numeral(-1, x.get_ebits()),
|
||||
bu.mk_numeral(0, x.get_sbits() - 2),
|
||||
bu.mk_numeral(1, 1) };
|
||||
result = bu.mk_concat(4, args);
|
||||
}
|
||||
else {
|
||||
app_ref unspec(m()), mask(m()), extra(m());
|
||||
unspec = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits());
|
||||
mask = bu.mk_concat(bu.mk_numeral(0, 1),
|
||||
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
|
||||
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
|
||||
bu.mk_numeral(1, 1))));
|
||||
expr * args[2] = { unspec, mask };
|
||||
result = m().mk_app(bu.get_fid(), OP_BOR, 2, args);
|
||||
}
|
||||
return BR_REWRITE_FULL;
|
||||
else
|
||||
result = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits());
|
||||
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
else {
|
||||
scoped_mpz rz(m_fm.mpq_manager());
|
||||
m_fm.to_ieee_bv_mpz(v, rz);
|
||||
|
||||
result = bu.mk_numeral(rational(rz), x.get_ebits() + x.get_sbits());
|
||||
return BR_DONE;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
def_module_params(module_name='rewriter',
|
||||
class_name='fpa_rewriter_params',
|
||||
export=True,
|
||||
params=(("hi_fp_unspecified", BOOL, True, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, and fp.to_real"),
|
||||
params=(("hi_fp_unspecified", BOOL, False, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, fp.to_real, and fp.to_ieee_bv"),
|
||||
))
|
||||
|
|
|
@ -277,6 +277,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
|||
tout << tmp << "\n";
|
||||
tout << result << "\n";
|
||||
);
|
||||
|
||||
TRACE("pb_validate",
|
||||
validate_rewrite(f, num_args, args, result););
|
||||
|
||||
|
|
|
@ -21,8 +21,10 @@ Revision History:
|
|||
#include"array_decl_plugin.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"seq_decl_plugin.h"
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"ast_pp.h"
|
||||
#include"for_each_expr.h"
|
||||
#include<strstream>
|
||||
|
||||
struct check_logic::imp {
|
||||
ast_manager & m;
|
||||
|
@ -31,6 +33,7 @@ struct check_logic::imp {
|
|||
bv_util m_bv_util;
|
||||
array_util m_ar_util;
|
||||
seq_util m_seq_util;
|
||||
datatype_util m_dt_util;
|
||||
bool m_uf; // true if the logic supports uninterpreted functions
|
||||
bool m_arrays; // true if the logic supports arbitrary arrays
|
||||
bool m_bv_arrays; // true if the logic supports only bv arrays
|
||||
|
@ -42,7 +45,7 @@ struct check_logic::imp {
|
|||
bool m_quantifiers; // true if the logic supports quantifiers
|
||||
bool m_unknown_logic;
|
||||
|
||||
imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m) {
|
||||
imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m), m_dt_util(m) {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -178,6 +181,11 @@ struct check_logic::imp {
|
|||
m_reals = true;
|
||||
m_quantifiers = false;
|
||||
}
|
||||
else if (logic == "QF_FD") {
|
||||
m_bvs = true;
|
||||
m_uf = true;
|
||||
m_ints = true;
|
||||
}
|
||||
else {
|
||||
m_unknown_logic = true;
|
||||
}
|
||||
|
@ -432,8 +440,13 @@ struct check_logic::imp {
|
|||
else if (fid == m_seq_util.get_family_id()) {
|
||||
// nothing to check
|
||||
}
|
||||
else if (fid == m_dt_util.get_family_id() && m_logic == "QF_FD") {
|
||||
// nothing to check
|
||||
}
|
||||
else {
|
||||
fail("logic does not support theory");
|
||||
std::stringstream strm;
|
||||
strm << "logic does not support theory " << m.get_family_name(fid);
|
||||
fail(strm.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -568,6 +568,7 @@ bool cmd_context::logic_has_bv_core(symbol const & s) const {
|
|||
s == "QF_FPBV" ||
|
||||
s == "QF_BVFP" ||
|
||||
s == "ALL" ||
|
||||
s == "QF_FD" ||
|
||||
s == "HORN";
|
||||
}
|
||||
|
||||
|
@ -622,7 +623,7 @@ bool cmd_context::logic_has_array() const {
|
|||
}
|
||||
|
||||
bool cmd_context::logic_has_datatype() const {
|
||||
return !has_logic();
|
||||
return !has_logic() || m_logic == "QF_FD";
|
||||
}
|
||||
|
||||
void cmd_context::init_manager_core(bool new_manager) {
|
||||
|
@ -705,7 +706,7 @@ void cmd_context::init_external_manager() {
|
|||
}
|
||||
|
||||
bool cmd_context::supported_logic(symbol const & s) const {
|
||||
return s == "QF_UF" || s == "UF" || s == "ALL" ||
|
||||
return s == "QF_UF" || s == "UF" || s == "ALL" || s == "QF_FD" ||
|
||||
logic_has_arith_core(s) || logic_has_bv_core(s) ||
|
||||
logic_has_array_core(s) || logic_has_seq_core(s) ||
|
||||
logic_has_horn(s) || logic_has_fpa_core(s);
|
||||
|
|
|
@ -87,3 +87,19 @@ void model_core::register_decl(func_decl * d, func_interp * fi) {
|
|||
}
|
||||
}
|
||||
|
||||
void model_core::unregister_decl(func_decl * d) {
|
||||
decl2expr::obj_map_entry * ec = m_interp.find_core(d);
|
||||
if (ec && ec->get_data().m_value != 0) {
|
||||
m_manager.dec_ref(ec->get_data().m_key);
|
||||
m_manager.dec_ref(ec->get_data().m_value);
|
||||
m_interp.remove(d);
|
||||
return;
|
||||
}
|
||||
|
||||
decl2finterp::obj_map_entry * ef = m_finterp.find_core(d);
|
||||
if (ef && ef->get_data().m_value != 0) {
|
||||
m_manager.dec_ref(ef->get_data().m_key);
|
||||
dealloc(ef->get_data().m_value);
|
||||
m_finterp.remove(d);
|
||||
}
|
||||
}
|
|
@ -60,6 +60,7 @@ public:
|
|||
|
||||
void register_decl(func_decl * d, expr * v);
|
||||
void register_decl(func_decl * f, func_interp * fi);
|
||||
void unregister_decl(func_decl * d);
|
||||
|
||||
virtual expr * get_some_value(sort * s) = 0;
|
||||
|
||||
|
|
|
@ -3075,45 +3075,51 @@ namespace sat {
|
|||
m_binary_clause_graph[l1.index()].push_back(l2);
|
||||
m_binary_clause_graph[l2.index()].push_back(l1);
|
||||
}
|
||||
while (!ps.empty()) {
|
||||
bool non_empty = true;
|
||||
m_seen[0].reset();
|
||||
while (non_empty) {
|
||||
literal_vector mutex;
|
||||
literal_set other(ps);
|
||||
while (!other.empty()) {
|
||||
literal_set conseq;
|
||||
literal p = other.pop();
|
||||
bool turn = false;
|
||||
m_reachable[turn] = ps;
|
||||
while (!m_reachable[turn].empty()) {
|
||||
literal p = m_reachable[turn].pop();
|
||||
if (m_seen[0].contains(p)) {
|
||||
continue;
|
||||
}
|
||||
m_reachable[turn].remove(p);
|
||||
m_seen[0].insert(p);
|
||||
mutex.push_back(p);
|
||||
if (other.empty()) {
|
||||
if (m_reachable[turn].empty()) {
|
||||
break;
|
||||
}
|
||||
get_reachable(p, other, conseq);
|
||||
other = conseq;
|
||||
m_reachable[!turn].reset();
|
||||
get_reachable(p, m_reachable[turn], m_reachable[!turn]);
|
||||
turn = !turn;
|
||||
}
|
||||
if (mutex.size() > 1) {
|
||||
mutexes.push_back(mutex);
|
||||
}
|
||||
for (unsigned i = 0; i < mutex.size(); ++i) {
|
||||
ps.erase(mutex[i]);
|
||||
}
|
||||
non_empty = !mutex.empty();
|
||||
}
|
||||
return l_true;
|
||||
}
|
||||
|
||||
void solver::get_reachable(literal p, literal_set const& goal, literal_set& reachable) {
|
||||
literal_set seen;
|
||||
literal_vector todo;
|
||||
todo.push_back(p);
|
||||
while (!todo.empty()) {
|
||||
p = todo.back();
|
||||
todo.pop_back();
|
||||
if (seen.contains(p)) {
|
||||
m_seen[1].reset();
|
||||
m_todo.reset();
|
||||
m_todo.push_back(p);
|
||||
while (!m_todo.empty()) {
|
||||
p = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
if (m_seen[1].contains(p)) {
|
||||
continue;
|
||||
}
|
||||
seen.insert(p);
|
||||
m_seen[1].insert(p);
|
||||
literal np = ~p;
|
||||
if (goal.contains(np)) {
|
||||
reachable.insert(np);
|
||||
}
|
||||
todo.append(m_binary_clause_graph[np.index()]);
|
||||
m_todo.append(m_binary_clause_graph[np.index()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3129,6 +3135,7 @@ namespace sat {
|
|||
if (is_sat != l_true) {
|
||||
return is_sat;
|
||||
}
|
||||
model mdl = get_model();
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
bool_var v = vars[i];
|
||||
switch (get_model()[v]) {
|
||||
|
@ -3137,7 +3144,9 @@ namespace sat {
|
|||
default: break;
|
||||
}
|
||||
}
|
||||
return get_consequences(asms, lits, conseq);
|
||||
is_sat = get_consequences(asms, lits, conseq);
|
||||
set_model(mdl);
|
||||
return is_sat;
|
||||
}
|
||||
|
||||
lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector<literal_vector>& conseq) {
|
||||
|
@ -3158,13 +3167,11 @@ namespace sat {
|
|||
while (!unfixed.empty()) {
|
||||
checkpoint();
|
||||
literal_set::iterator it = unfixed.begin(), end = unfixed.end();
|
||||
unsigned chunk_size = 100;
|
||||
for (; it != end && chunk_size > 0; ++it) {
|
||||
for (; it != end; ++it) {
|
||||
literal lit = *it;
|
||||
if (value(lit) != l_undef) {
|
||||
continue;
|
||||
}
|
||||
--chunk_size;
|
||||
push();
|
||||
assign(~lit, justification());
|
||||
propagate(false);
|
||||
|
|
|
@ -447,6 +447,9 @@ namespace sat {
|
|||
|
||||
u_map<index_set> m_antecedents;
|
||||
vector<literal_vector> m_binary_clause_graph;
|
||||
literal_set m_reachable[2];
|
||||
literal_set m_seen[2];
|
||||
literal_vector m_todo;
|
||||
|
||||
void extract_assumptions(literal lit, index_set& s);
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ Notes:
|
|||
#include "filter_model_converter.h"
|
||||
#include "bit_blaster_model_converter.h"
|
||||
#include "ast_translation.h"
|
||||
#include "ast_util.h"
|
||||
|
||||
// incremental SAT solver.
|
||||
class inc_sat_solver : public solver {
|
||||
|
@ -232,6 +233,41 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) {
|
||||
TRACE("sat", tout << assumptions << "\n" << vars << "\n";);
|
||||
sat::literal_vector asms;
|
||||
sat::bool_var_vector bvars;
|
||||
vector<sat::literal_vector> lconseq;
|
||||
dep2asm_t dep2asm;
|
||||
m_solver.pop_to_base_level();
|
||||
lbool r = internalize_formulas();
|
||||
if (r != l_true) return r;
|
||||
r = internalize_assumptions(assumptions.size(), assumptions.c_ptr(), dep2asm);
|
||||
if (r != l_true) return r;
|
||||
r = internalize_vars(vars, bvars);
|
||||
|
||||
r = m_solver.get_consequences(m_asms, bvars, lconseq);
|
||||
if (r != l_true) return r;
|
||||
|
||||
// build map from bound variables to
|
||||
// the consequences that cover them.
|
||||
u_map<unsigned> bool_var2conseq;
|
||||
for (unsigned i = 0; i < lconseq.size(); ++i) {
|
||||
TRACE("sat", tout << lconseq[i] << "\n";);
|
||||
bool_var2conseq.insert(lconseq[i][0].var(), i);
|
||||
}
|
||||
|
||||
// extract original fixed variables
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
expr_ref cons(m);
|
||||
if (extract_fixed_variable(dep2asm, vars[i], bool_var2conseq, lconseq, cons)) {
|
||||
conseq.push_back(cons);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
|
||||
sat::literal_vector ls;
|
||||
u_map<expr*> lit2var;
|
||||
|
@ -359,6 +395,106 @@ private:
|
|||
return res;
|
||||
}
|
||||
|
||||
lbool internalize_vars(expr_ref_vector const& vars, sat::bool_var_vector& bvars) {
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
internalize_var(vars[i], bvars);
|
||||
}
|
||||
return l_true;
|
||||
}
|
||||
|
||||
bool internalize_var(expr* v, sat::bool_var_vector& bvars) {
|
||||
obj_map<func_decl, expr*> const& const2bits = m_bb_rewriter->const2bits();
|
||||
expr* bv;
|
||||
bv_util bvutil(m);
|
||||
bool internalized = false;
|
||||
if (is_uninterp_const(v) && m.is_bool(v)) {
|
||||
sat::bool_var b = m_map.to_bool_var(v);
|
||||
|
||||
if (b != sat::null_bool_var) {
|
||||
bvars.push_back(b);
|
||||
internalized = true;
|
||||
}
|
||||
}
|
||||
else if (is_uninterp_const(v) && const2bits.find(to_app(v)->get_decl(), bv)) {
|
||||
SASSERT(bvutil.is_bv(bv));
|
||||
app* abv = to_app(bv);
|
||||
internalized = true;
|
||||
unsigned sz = abv->get_num_args();
|
||||
for (unsigned j = 0; j < sz; ++j) {
|
||||
SASSERT(is_uninterp_const(abv->get_arg(j)));
|
||||
sat::bool_var b = m_map.to_bool_var(abv->get_arg(j));
|
||||
if (b == sat::null_bool_var) {
|
||||
internalized = false;
|
||||
}
|
||||
else {
|
||||
bvars.push_back(b);
|
||||
}
|
||||
}
|
||||
CTRACE("sat", internalized, tout << "var: "; for (unsigned j = 0; j < sz; ++j) tout << bvars[bvars.size()-sz+j] << " "; tout << "\n";);
|
||||
}
|
||||
else if (is_uninterp_const(v) && bvutil.is_bv(v)) {
|
||||
// variable does not occur in assertions, so is unconstrained.
|
||||
}
|
||||
CTRACE("sat", !internalized, tout << "unhandled variable " << mk_pp(v, m) << "\n";);
|
||||
return internalized;
|
||||
}
|
||||
|
||||
bool extract_fixed_variable(dep2asm_t& dep2asm, expr* v, u_map<unsigned> const& bool_var2conseq, vector<sat::literal_vector> const& lconseq, expr_ref& conseq) {
|
||||
u_map<expr*> asm2dep;
|
||||
extract_asm2dep(dep2asm, asm2dep);
|
||||
|
||||
sat::bool_var_vector bvars;
|
||||
if (!internalize_var(v, bvars)) {
|
||||
return false;
|
||||
}
|
||||
sat::literal_vector value;
|
||||
sat::literal_set premises;
|
||||
for (unsigned i = 0; i < bvars.size(); ++i) {
|
||||
unsigned index;
|
||||
if (bool_var2conseq.find(bvars[i], index)) {
|
||||
value.push_back(lconseq[index][0]);
|
||||
for (unsigned j = 1; j < lconseq[index].size(); ++j) {
|
||||
premises.insert(lconseq[index][j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
TRACE("sat", tout << "variable is not bound " << mk_pp(v, m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
expr_ref val(m);
|
||||
expr_ref_vector conj(m);
|
||||
internalize_value(value, v, val);
|
||||
while (!premises.empty()) {
|
||||
expr* e = 0;
|
||||
VERIFY(asm2dep.find(premises.pop().index(), e));
|
||||
conj.push_back(e);
|
||||
}
|
||||
conseq = m.mk_implies(mk_and(conj), val);
|
||||
return true;
|
||||
}
|
||||
|
||||
void internalize_value(sat::literal_vector const& value, expr* v, expr_ref& val) {
|
||||
bv_util bvutil(m);
|
||||
if (is_uninterp_const(v) && m.is_bool(v)) {
|
||||
SASSERT(value.size() == 1);
|
||||
val = value[0].sign() ? m.mk_not(v) : v;
|
||||
}
|
||||
else if (is_uninterp_const(v) && bvutil.is_bv_sort(m.get_sort(v))) {
|
||||
SASSERT(value.size() == bvutil.get_bv_size(v));
|
||||
rational r(0);
|
||||
for (unsigned i = 0; i < value.size(); ++i) {
|
||||
if (!value[i].sign()) {
|
||||
r += rational(2).expt(i);
|
||||
}
|
||||
}
|
||||
val = m.mk_eq(v, bvutil.mk_numeral(r, value.size()));
|
||||
}
|
||||
else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
lbool internalize_formulas() {
|
||||
if (m_fmls_head == m_fmls.size()) {
|
||||
return l_true;
|
||||
|
@ -395,13 +531,17 @@ private:
|
|||
SASSERT(dep2asm.size() == m_asms.size());
|
||||
}
|
||||
|
||||
void extract_core(dep2asm_t& dep2asm) {
|
||||
u_map<expr*> asm2dep;
|
||||
void extract_asm2dep(dep2asm_t const& dep2asm, u_map<expr*>& asm2dep) {
|
||||
dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end();
|
||||
for (; it != end; ++it) {
|
||||
expr* e = it->m_key;
|
||||
asm2dep.insert(it->m_value.index(), e);
|
||||
}
|
||||
}
|
||||
|
||||
void extract_core(dep2asm_t& dep2asm) {
|
||||
u_map<expr*> asm2dep;
|
||||
extract_asm2dep(dep2asm, asm2dep);
|
||||
sat::literal_vector const& core = m_solver.get_core();
|
||||
TRACE("sat",
|
||||
dep2asm_t::iterator it2 = dep2asm.begin();
|
||||
|
@ -440,7 +580,7 @@ private:
|
|||
}
|
||||
|
||||
void extract_model() {
|
||||
TRACE("sat", tout << "retrieve model\n";);
|
||||
TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";);
|
||||
if (!m_solver.model_is_current()) {
|
||||
m_model = 0;
|
||||
return;
|
||||
|
|
|
@ -40,9 +40,9 @@ namespace sat {
|
|||
typedef unsigned bool_var;
|
||||
|
||||
typedef svector<bool_var> bool_var_vector;
|
||||
|
||||
|
||||
const bool_var null_bool_var = UINT_MAX >> 1;
|
||||
|
||||
|
||||
/**
|
||||
\brief The literal b is represented by the value 2*b, and
|
||||
the literal (not b) by the value 2*b + 1
|
||||
|
@ -54,33 +54,33 @@ namespace sat {
|
|||
literal():m_val(null_bool_var << 1) {
|
||||
SASSERT(var() == null_bool_var && !sign());
|
||||
}
|
||||
|
||||
|
||||
literal(bool_var v, bool _sign):
|
||||
m_val((v << 1) + static_cast<unsigned>(_sign)) {
|
||||
SASSERT(var() == v);
|
||||
SASSERT(sign() == _sign);
|
||||
}
|
||||
|
||||
bool_var var() const {
|
||||
return m_val >> 1;
|
||||
|
||||
bool_var var() const {
|
||||
return m_val >> 1;
|
||||
}
|
||||
|
||||
|
||||
bool sign() const {
|
||||
return m_val & 1;
|
||||
return m_val & 1;
|
||||
}
|
||||
|
||||
literal unsign() const {
|
||||
return literal(m_val & ~1);
|
||||
}
|
||||
|
||||
|
||||
unsigned index() const {
|
||||
return m_val;
|
||||
}
|
||||
|
||||
|
||||
void neg() {
|
||||
m_val = m_val ^ 1;
|
||||
}
|
||||
|
||||
|
||||
friend literal operator~(literal l) {
|
||||
return literal(l.m_val ^ 1);
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ namespace sat {
|
|||
typedef approx_set_tpl<literal, literal2unsigned, unsigned> literal_approx_set;
|
||||
|
||||
typedef approx_set_tpl<bool_var, u2u, unsigned> var_approx_set;
|
||||
|
||||
|
||||
enum phase {
|
||||
POS_PHASE, NEG_PHASE, PHASE_NOT_AVAILABLE
|
||||
};
|
||||
|
@ -128,7 +128,7 @@ namespace sat {
|
|||
typedef ptr_vector<clause> clause_vector;
|
||||
|
||||
class solver_exception : public default_exception {
|
||||
public:
|
||||
public:
|
||||
solver_exception(char const * msg):default_exception(msg) {}
|
||||
};
|
||||
|
||||
|
@ -138,7 +138,7 @@ namespace sat {
|
|||
|
||||
inline lbool value_at(bool_var v, model const & m) { return m[v]; }
|
||||
inline lbool value_at(literal l, model const & m) { lbool r = value_at(l.var(), m); return l.sign() ? ~r : r; }
|
||||
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, model const & m) {
|
||||
bool first = true;
|
||||
for (bool_var v = 0; v < m.size(); v++) {
|
||||
|
@ -154,19 +154,20 @@ namespace sat {
|
|||
svector<unsigned> m_set;
|
||||
public:
|
||||
typedef svector<unsigned>::const_iterator iterator;
|
||||
void insert(unsigned v) {
|
||||
void insert(unsigned v) {
|
||||
m_in_set.reserve(v+1, false);
|
||||
if (m_in_set[v])
|
||||
return;
|
||||
m_in_set[v] = true;
|
||||
m_set.push_back(v);
|
||||
if (m_in_set[v])
|
||||
return;
|
||||
m_in_set[v] = true;
|
||||
m_set.push_back(v);
|
||||
}
|
||||
|
||||
void remove(unsigned v) {
|
||||
if (contains(v)) {
|
||||
m_in_set[v] = false;
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < m_set.size() && m_set[i] != v; ++i);
|
||||
for (i = 0; i < m_set.size() && m_set[i] != v; ++i)
|
||||
;
|
||||
SASSERT(i < m_set.size());
|
||||
m_set[i] = m_set.back();
|
||||
m_set.pop_back();
|
||||
|
@ -178,22 +179,22 @@ namespace sat {
|
|||
m_set = other.m_set;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool contains(unsigned v) const {
|
||||
return v < m_in_set.size() && m_in_set[v] != 0;
|
||||
|
||||
bool contains(unsigned v) const {
|
||||
return v < m_in_set.size() && m_in_set[v] != 0;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_set.empty();
|
||||
|
||||
bool empty() const {
|
||||
return m_set.empty();
|
||||
}
|
||||
|
||||
// erase some variable from the set
|
||||
unsigned erase() {
|
||||
SASSERT(!empty());
|
||||
unsigned v = m_set.back();
|
||||
m_set.pop_back();
|
||||
m_in_set[v] = false;
|
||||
return v;
|
||||
unsigned erase() {
|
||||
SASSERT(!empty());
|
||||
unsigned v = m_set.back();
|
||||
m_set.pop_back();
|
||||
m_in_set[v] = false;
|
||||
return v;
|
||||
}
|
||||
unsigned size() const { return m_set.size(); }
|
||||
iterator begin() const { return m_set.begin(); }
|
||||
|
@ -239,6 +240,18 @@ namespace sat {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
literal_set& operator=(literal_vector const& v) {
|
||||
reset();
|
||||
for (unsigned i = 0; i < v.size(); ++i) insert(v[i]);
|
||||
return *this;
|
||||
}
|
||||
literal_set& operator=(literal_set const& other) {
|
||||
if (this != &other) {
|
||||
m_set = other.m_set;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void insert(literal l) { m_set.insert(l.index()); }
|
||||
void remove(literal l) { m_set.remove(l.index()); }
|
||||
literal pop() { return to_literal(m_set.erase()); }
|
||||
|
@ -268,10 +281,10 @@ namespace sat {
|
|||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct mem_stat {
|
||||
};
|
||||
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, mem_stat const & m) {
|
||||
double mem = static_cast<double>(memory::get_allocation_size())/static_cast<double>(1024*1024);
|
||||
out << " :memory " << std::fixed << std::setprecision(2) << mem;
|
||||
|
|
|
@ -23,9 +23,9 @@ Revision History:
|
|||
|
||||
namespace smt {
|
||||
|
||||
template<typename Ext>
|
||||
template<typename Ext>
|
||||
expr * theory_arith<Ext>::mk_nary_mul(unsigned sz, expr * const * args, bool is_int) {
|
||||
if (sz == 0)
|
||||
if (sz == 0)
|
||||
return m_util.mk_numeral(rational(1), is_int);
|
||||
if (sz == 1)
|
||||
return args[0];
|
||||
|
@ -36,21 +36,21 @@ namespace smt {
|
|||
return m_util.mk_mul(sz, args);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
template<typename Ext>
|
||||
expr * theory_arith<Ext>::mk_nary_add(unsigned sz, expr * const * args, bool is_int) {
|
||||
if (sz == 0)
|
||||
if (sz == 0)
|
||||
return m_util.mk_numeral(rational(0), is_int);
|
||||
if (sz == 1)
|
||||
return args[0];
|
||||
return m_util.mk_add(sz, args);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
template<typename Ext>
|
||||
expr * theory_arith<Ext>::mk_nary_add(unsigned sz, expr * const * args) {
|
||||
SASSERT(sz != 0);
|
||||
return mk_nary_add(sz, args, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Insert v into vars and already_found if v is not already in already_found.
|
||||
*/
|
||||
|
@ -92,21 +92,21 @@ namespace smt {
|
|||
theory_var s = r.get_base_var();
|
||||
// ignore quasi base vars... actually they should not be used if the problem is non linear...
|
||||
if (is_quasi_base(s))
|
||||
continue;
|
||||
continue;
|
||||
// If s is a base variable different from v and it is free, then this row can be ignored.
|
||||
// It doesn't need to be part of the non linear cluster. For all purposes, this variable
|
||||
// was eliminated by substitution.
|
||||
if (is_free(s) && s != v)
|
||||
continue;
|
||||
continue;
|
||||
typename vector<row_entry>::const_iterator it2 = r.begin_entries();
|
||||
typename vector<row_entry>::const_iterator end2 = r.end_entries();
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (!it2->is_dead() && !is_fixed(it2->m_var))
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (!it2->is_dead() && !is_fixed(it2->m_var))
|
||||
mark_var(it2->m_var, vars, already_found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Store in vars the variables that are in the non linear cluster of constraints,
|
||||
and are not satisfied by the current assignment.
|
||||
|
@ -123,7 +123,7 @@ namespace smt {
|
|||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
expr * n = var2expr(v);
|
||||
if (ctx.is_relevant(n))
|
||||
if (ctx.is_relevant(n))
|
||||
mark_var(v, vars, already_found);
|
||||
}
|
||||
for (unsigned idx = 0; idx < vars.size(); idx++) {
|
||||
|
@ -134,7 +134,7 @@ namespace smt {
|
|||
svector<theory_var>::const_iterator it = vars.begin();
|
||||
svector<theory_var>::const_iterator end = vars.end();
|
||||
for (; it != end; ++it) tout << "v" << *it << " ";
|
||||
tout << "\n";);
|
||||
tout << "\n";);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,7 +148,7 @@ namespace smt {
|
|||
|
||||
\remark if a variables has an even number of occurrences, then
|
||||
I consider that it has a bound associated with it.
|
||||
|
||||
|
||||
Examples:
|
||||
1) Assume x1, x4 have bounds:
|
||||
analyze_monomial(x1 * x2 * x2 * x3 * x3 * x3 * x4)
|
||||
|
@ -168,24 +168,24 @@ namespace smt {
|
|||
int idx = 0;
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (arg == var) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (power % 2 == 1 && is_free(var)) {
|
||||
c++;
|
||||
free_var_idx = idx;
|
||||
if (c > 1)
|
||||
return std::make_pair(2, free_var_idx);
|
||||
}
|
||||
var = arg;
|
||||
power = 1;
|
||||
idx++;
|
||||
}
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (arg == var) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (power % 2 == 1 && is_free(var)) {
|
||||
c++;
|
||||
free_var_idx = idx;
|
||||
if (c > 1)
|
||||
return std::make_pair(2, free_var_idx);
|
||||
}
|
||||
var = arg;
|
||||
power = 1;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
if (power % 2 == 1 && is_free(var)) {
|
||||
c++;
|
||||
|
@ -257,17 +257,17 @@ namespace smt {
|
|||
unsigned j;
|
||||
for (j = 0; j < to_app(m)->get_num_args(); j++) {
|
||||
expr * arg = to_app(m)->get_arg(j);
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (var == arg) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (curr_idx == i)
|
||||
return var_power_pair(var, power);
|
||||
curr_idx++;
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (var == arg) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (curr_idx == i)
|
||||
return var_power_pair(var, power);
|
||||
curr_idx++;
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
|
@ -289,24 +289,24 @@ namespace smt {
|
|||
bound * l = lower(v);
|
||||
bound * u = upper(v);
|
||||
if (l && u) {
|
||||
return interval(m_dep_manager,
|
||||
l->get_value().get_rational().to_rational(),
|
||||
return interval(m_dep_manager,
|
||||
l->get_value().get_rational().to_rational(),
|
||||
!l->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
m_dep_manager.mk_leaf(l),
|
||||
u->get_value().get_rational().to_rational(),
|
||||
u->get_value().get_rational().to_rational(),
|
||||
!u->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
m_dep_manager.mk_leaf(u));
|
||||
}
|
||||
else if (l) {
|
||||
return interval(m_dep_manager,
|
||||
l->get_value().get_rational().to_rational(),
|
||||
l->get_value().get_rational().to_rational(),
|
||||
!l->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
true,
|
||||
m_dep_manager.mk_leaf(l));
|
||||
}
|
||||
else if (u) {
|
||||
return interval(m_dep_manager,
|
||||
u->get_value().get_rational().to_rational(),
|
||||
u->get_value().get_rational().to_rational(),
|
||||
!u->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
false,
|
||||
m_dep_manager.mk_leaf(u));
|
||||
|
@ -333,12 +333,12 @@ namespace smt {
|
|||
void theory_arith<Ext>::mul_bound_of(expr * var, unsigned power, interval & target) {
|
||||
theory_var v = expr2var(var);
|
||||
interval i = mk_interval_for(v);
|
||||
|
||||
TRACE("non_linear",
|
||||
|
||||
TRACE("non_linear",
|
||||
display_interval(tout << "bound: ",i); tout << i << "\n";
|
||||
tout << mk_pp(var, get_manager()) << "\n";
|
||||
tout << "power " << power << ": " << expt(i, power) << "\n";
|
||||
display_interval(tout << "target before: ", target); tout << "\n";);
|
||||
display_interval(tout << "target before: ", target); tout << "\n";);
|
||||
i.expt(power);
|
||||
target *= i;
|
||||
TRACE("non_linear", display_interval(tout << "target after: ", target); tout << "\n";);
|
||||
|
@ -348,7 +348,7 @@ namespace smt {
|
|||
\brief Evaluate the given expression using interval arithmetic.
|
||||
|
||||
- If a subexpression is internalized, then mk_interval_for is used to
|
||||
compute its interval.
|
||||
compute its interval.
|
||||
|
||||
- Only +, *, and numerals are handled.
|
||||
*/
|
||||
|
@ -382,7 +382,7 @@ namespace smt {
|
|||
interval it = evaluate_as_interval(var);
|
||||
it.expt(power);
|
||||
r *= it;
|
||||
}
|
||||
}
|
||||
TRACE("cross_nested_eval_bug", display_nested_form(tout, n); tout << "\ninterval: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
@ -424,7 +424,7 @@ namespace smt {
|
|||
ptr_vector<void>::const_iterator end = bounds.end();
|
||||
for (; it != end; ++it) {
|
||||
bound * b = static_cast<bound*>(*it);
|
||||
accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,7 +476,7 @@ namespace smt {
|
|||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::update_bounds_using_interval(expr * n, interval const & i) {
|
||||
SASSERT(expr2var(n) != null_theory_var);
|
||||
|
@ -510,7 +510,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
/**
|
||||
\brief Propagate a bound to the i-th variable of the given monomial
|
||||
\brief Propagate a bound to the i-th variable of the given monomial
|
||||
using the bounds of m and other variables in m.
|
||||
|
||||
\remark We do not support roots in interval... so, if the i-th var has power != 1
|
||||
|
@ -523,7 +523,7 @@ namespace smt {
|
|||
var_power_pair p = get_var_and_degree(m, i);
|
||||
expr * v = p.first;
|
||||
unsigned power = p.second;
|
||||
TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) <<
|
||||
TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) <<
|
||||
"\npower: " << power << "\n";);
|
||||
if (power != 1)
|
||||
return false; // TODO: remove, when the n-th root is implemented in interval.
|
||||
|
@ -556,7 +556,7 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
bool theory_arith<Ext>::propagate_nl_bound(expr * m, int i) {
|
||||
TRACE("propagate_nl_bound", tout << "propagate using i: " << i << "\n"; display_monomial(tout, m); tout << "\n";);
|
||||
if (i == -1)
|
||||
if (i == -1)
|
||||
return propagate_nl_upward(m);
|
||||
else
|
||||
return propagate_nl_downward(m, i);
|
||||
|
@ -589,10 +589,8 @@ namespace smt {
|
|||
m_dep_manager.reset();
|
||||
bool propagated = false;
|
||||
context & ctx = get_context();
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
for (unsigned i = 0; i < m_nl_monomials.size(); i++) {
|
||||
theory_var v = m_nl_monomials[i];
|
||||
expr * m = var2expr(v);
|
||||
if (!ctx.is_relevant(m))
|
||||
continue;
|
||||
|
@ -657,13 +655,13 @@ namespace smt {
|
|||
rational val(1);
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var curr = expr2var(arg);
|
||||
SASSERT(curr != null_theory_var);
|
||||
val *= get_value(curr, computed_epsilon);
|
||||
theory_var curr = expr2var(arg);
|
||||
SASSERT(curr != null_theory_var);
|
||||
val *= get_value(curr, computed_epsilon);
|
||||
}
|
||||
return get_value(v, computed_epsilon) == val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Return true if for every monomial x_1 * ... * x_n,
|
||||
|
@ -691,11 +689,11 @@ namespace smt {
|
|||
/**
|
||||
\brief Try to find an integer variable for performing branching
|
||||
in the non linear cluster.
|
||||
|
||||
|
||||
The idea is select a variable in a monomial with an invalid
|
||||
assignment. I give preference to variables with small ranges.
|
||||
If no variable is bounded, then select a random one.
|
||||
|
||||
|
||||
Free variables are not considered.
|
||||
*/
|
||||
template<typename Ext>
|
||||
|
@ -705,44 +703,42 @@ namespace smt {
|
|||
theory_var target = null_theory_var;
|
||||
bool bounded = false;
|
||||
unsigned n = 0;
|
||||
numeral range;
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
if (is_real(v))
|
||||
numeral range;
|
||||
for (unsigned i = 0; i < m_nl_monomials.size(); i++) {
|
||||
theory_var v = m_nl_monomials[i];
|
||||
if (is_real(v))
|
||||
continue;
|
||||
bool computed_epsilon = false;
|
||||
bool r = check_monomial_assignment(v, computed_epsilon);
|
||||
bool r = check_monomial_assignment(v, computed_epsilon);
|
||||
SASSERT(!computed_epsilon); // integer variables do not use epsilon
|
||||
if (!r) {
|
||||
expr * m = get_enode(v)->get_owner();
|
||||
SASSERT(is_pure_monomial(m));
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var curr = ctx.get_enode(arg)->get_th_var(get_id());
|
||||
TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";);
|
||||
if (!is_fixed(curr) && is_int(curr)) {
|
||||
if (is_bounded(curr)) {
|
||||
numeral new_range;
|
||||
new_range = upper_bound(curr).get_rational();
|
||||
new_range -= lower_bound(curr).get_rational();
|
||||
if (!bounded || new_range < range) {
|
||||
target = curr;
|
||||
range = new_range;
|
||||
bounded = true;
|
||||
}
|
||||
}
|
||||
else if (!bounded) {
|
||||
n++;
|
||||
TRACE("nl_branching", tout << "n: " << n << "\n";);
|
||||
if (m_random()%n == 0)
|
||||
target = curr;
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
TRACE("nl_branching", tout << "after target: v" << target << "\n";);
|
||||
theory_var curr = ctx.get_enode(arg)->get_th_var(get_id());
|
||||
TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";);
|
||||
if (!is_fixed(curr) && is_int(curr)) {
|
||||
if (is_bounded(curr)) {
|
||||
numeral new_range;
|
||||
new_range = upper_bound(curr).get_rational();
|
||||
new_range -= lower_bound(curr).get_rational();
|
||||
if (!bounded || new_range < range) {
|
||||
target = curr;
|
||||
range = new_range;
|
||||
bounded = true;
|
||||
}
|
||||
}
|
||||
else if (!bounded) {
|
||||
n++;
|
||||
TRACE("nl_branching", tout << "n: " << n << "\n";);
|
||||
if (m_random()%n == 0)
|
||||
target = curr;
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
TRACE("nl_branching", tout << "after target: v" << target << "\n";);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -762,7 +758,7 @@ namespace smt {
|
|||
m_stats.m_nl_branching++;
|
||||
SASSERT(is_int(v));
|
||||
expr * bound = 0;
|
||||
if (lower(v))
|
||||
if (lower(v))
|
||||
bound = m_util.mk_le(var2expr(v), m_util.mk_numeral(lower_bound(v).get_rational().to_rational(), true));
|
||||
else if (upper(v))
|
||||
bound = m_util.mk_ge(var2expr(v), m_util.mk_numeral(upper_bound(v).get_rational().to_rational(), true));
|
||||
|
@ -787,14 +783,14 @@ namespace smt {
|
|||
unsigned num_nl_vars = 0;
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var)) {
|
||||
num_nl_vars++;
|
||||
}
|
||||
else {
|
||||
if (lower_bound(_var).is_zero())
|
||||
return true;
|
||||
}
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var)) {
|
||||
num_nl_vars++;
|
||||
}
|
||||
else {
|
||||
if (lower_bound(_var).is_zero())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return num_nl_vars <= 1;
|
||||
}
|
||||
|
@ -809,9 +805,9 @@ namespace smt {
|
|||
numeral r(1);
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var))
|
||||
r *= lower_bound(_var).get_rational();
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var))
|
||||
r *= lower_bound(_var).get_rational();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -825,9 +821,9 @@ namespace smt {
|
|||
SASSERT(is_pure_monomial(m));
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var))
|
||||
return arg;
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var))
|
||||
return arg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -886,7 +882,7 @@ namespace smt {
|
|||
}
|
||||
else {
|
||||
// One of the x_i variables is zero,
|
||||
// or all of them are assigned.
|
||||
// or all of them are assigned.
|
||||
|
||||
// Assert the equality
|
||||
// (= (* x_1 ... x_n) k)
|
||||
|
@ -908,45 +904,45 @@ namespace smt {
|
|||
|
||||
SASSERT(is_pure_monomial(m));
|
||||
bool found_zero = false;
|
||||
for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var)) {
|
||||
bound * l = lower(_var);
|
||||
bound * u = upper(_var);
|
||||
if (l->get_value().is_zero()) {
|
||||
/* if zero was found, then it is the explanation */
|
||||
SASSERT(k.is_zero());
|
||||
found_zero = true;
|
||||
m_tmp_lit_set.reset();
|
||||
m_tmp_eq_set.reset();
|
||||
new_lower->m_lits.reset();
|
||||
new_lower->m_eqs.reset();
|
||||
}
|
||||
for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var)) {
|
||||
bound * l = lower(_var);
|
||||
bound * u = upper(_var);
|
||||
if (l->get_value().is_zero()) {
|
||||
/* if zero was found, then it is the explanation */
|
||||
SASSERT(k.is_zero());
|
||||
found_zero = true;
|
||||
m_tmp_lit_set.reset();
|
||||
m_tmp_eq_set.reset();
|
||||
new_lower->m_lits.reset();
|
||||
new_lower->m_eqs.reset();
|
||||
}
|
||||
accumulate_justification(*l, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
|
||||
TRACE("non_linear",
|
||||
|
||||
TRACE("non_linear",
|
||||
for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_lower->m_lits[j]);
|
||||
tout << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
|
||||
|
||||
accumulate_justification(*u, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
|
||||
TRACE("non_linear",
|
||||
|
||||
TRACE("non_linear",
|
||||
for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_lower->m_lits[j]);
|
||||
tout << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
new_upper->m_lits.append(new_lower->m_lits);
|
||||
new_upper->m_eqs.append(new_lower->m_eqs);
|
||||
|
||||
TRACE("non_linear",
|
||||
TRACE("non_linear",
|
||||
tout << "lower: " << new_lower << " upper: " << new_upper << "\n";
|
||||
for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_upper->m_lits[j]);
|
||||
|
@ -965,10 +961,19 @@ namespace smt {
|
|||
bool theory_arith<Ext>::propagate_linear_monomials() {
|
||||
TRACE("non_linear", tout << "propagating linear monomials...\n";);
|
||||
bool p = false;
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
// CMW: m_nl_monomials is sometimes modified while executing
|
||||
// propagate_linear_monomial(...), invalidating the iterator `it'.
|
||||
// (Via the relevancy propagation that internalizes a new axiom
|
||||
// in mk_div_axiom and possibly others.) I'm replacing the iterator
|
||||
// with an index `i'.
|
||||
|
||||
// Was previously:
|
||||
// svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
// svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
// for (; it != end; ++it) {
|
||||
// theory_var v = *it;
|
||||
for (unsigned i = 0; i < m_nl_monomials.size(); i++) {
|
||||
theory_var v = m_nl_monomials[i];
|
||||
if (propagate_linear_monomial(v))
|
||||
p = true;
|
||||
}
|
||||
|
@ -979,9 +984,9 @@ namespace smt {
|
|||
/*
|
||||
Interval arithmetic does not satisfy distributivity.
|
||||
Actually, it satisfies the sub-distributivity property:
|
||||
|
||||
|
||||
x*(y + z) \subseteq x*y + x*z
|
||||
|
||||
|
||||
The sub-distributivity property only holds if condensation
|
||||
is not used. For example:
|
||||
|
||||
|
@ -995,11 +1000,11 @@ namespace smt {
|
|||
|
||||
x*(x^3+1) = [-7, 14]
|
||||
x^4 + x = [-2, 17]
|
||||
|
||||
|
||||
This weakness of AI is known as the "dependency problem",
|
||||
which comes from the decorrelation of the multiple occurrences
|
||||
of one variable during interval evaluation.
|
||||
|
||||
|
||||
Given a polynomial:
|
||||
p(x) = a_0 + a_1 * x + ... + a_n * x^n
|
||||
The horner extension is:
|
||||
|
@ -1009,13 +1014,13 @@ namespace smt {
|
|||
h_p(x) = x(2 + x^3(1 + x))
|
||||
|
||||
The horner extension evaluates tighter intervals when
|
||||
condensation is not used.
|
||||
condensation is not used.
|
||||
|
||||
Remark: there is no guarantee that horner extension will
|
||||
provide a tighter interval than a sum of monomials when
|
||||
condensation is used.
|
||||
|
||||
For multivariate polynomials nested (or cross nested) forms
|
||||
For multivariate polynomials nested (or cross nested) forms
|
||||
are used. The idea is to select one variable, and pretend the
|
||||
other are parameters. The horner form is computed for the selected
|
||||
variable, and the computation continues for the polynomials on the
|
||||
|
@ -1027,13 +1032,13 @@ namespace smt {
|
|||
|
||||
p(x) = a*x^n + b*x^{n+m} for n >= m
|
||||
is equivalent to
|
||||
|
||||
|
||||
b*x^{n-m}*[(x^{m} + a/(2b))^2 - (a/2b)^2]
|
||||
|
||||
|
||||
This polynomial provides tight bound when n and m have the same parity and:
|
||||
1) a*b > 0 and (lower(x) >= 0 or upper(x)^m <= -a/b)
|
||||
2) a*b < 0 and (upper(x) <= 0 or lower(x)^m >= a/b)
|
||||
|
||||
|
||||
This polynomial also provides tight bounds when n = m,
|
||||
and the polynomial is simplified to, and n and m may have arbitrary parities:
|
||||
|
||||
|
@ -1047,7 +1052,7 @@ namespace smt {
|
|||
If we compute the bounds for x^2 - x we obtain
|
||||
(-oo, oo).
|
||||
|
||||
On the other hand, if we compute the bounds for
|
||||
On the other hand, if we compute the bounds for
|
||||
(x - 1/2)^2 - 1/4
|
||||
we obtain the bounds (0, oo), and the inconsistency
|
||||
is detected.
|
||||
|
@ -1055,8 +1060,8 @@ namespace smt {
|
|||
Remark: In Z3, I condensate multiple occurrences of a variable
|
||||
when evaluating monomials. So, the interval for a monomial is
|
||||
always tight.
|
||||
|
||||
Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3,
|
||||
|
||||
Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3,
|
||||
if intersection(Vars(M1), union(Vars(M2), Vars(M3))) = empty-set,
|
||||
|
||||
Remark: A trivial consequence of Moore's theorem for interval
|
||||
|
@ -1066,7 +1071,7 @@ namespace smt {
|
|||
|
||||
/**
|
||||
\brief Check whether the same variable occurs in two different monomials.
|
||||
|
||||
|
||||
\remark Fixed variables are ignored.
|
||||
|
||||
\remark A trivial consequence of Moore's theorem for interval
|
||||
|
@ -1208,7 +1213,7 @@ namespace smt {
|
|||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the number of occurrences in the result vector.
|
||||
typename var2num_occs::iterator it2 = m_var2num_occs.begin();
|
||||
typename var2num_occs::iterator end2 = m_var2num_occs.end();
|
||||
|
@ -1263,14 +1268,14 @@ namespace smt {
|
|||
m_nl_new_exprs.push_back(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Return true if var only occurs in two monovariate monomials,
|
||||
and return its power and coefficients and these monomials.
|
||||
The arguments i1 and i2 contain the position in p of the two monomials.
|
||||
*/
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::in_monovariate_monomials(sbuffer<coeff_expr> & p, expr * var,
|
||||
bool theory_arith<Ext>::in_monovariate_monomials(sbuffer<coeff_expr> & p, expr * var,
|
||||
unsigned & i1, rational & c1, unsigned & n1, unsigned & i2, rational & c2, unsigned & n2) {
|
||||
int idx = 0;
|
||||
#define SET_RESULT(POWER) { \
|
||||
|
@ -1289,7 +1294,7 @@ namespace smt {
|
|||
else \
|
||||
return false; \
|
||||
}
|
||||
|
||||
|
||||
typename sbuffer<coeff_expr>::const_iterator it = p.begin();
|
||||
typename sbuffer<coeff_expr>::const_iterator end = p.end();
|
||||
for (unsigned i = 0; it != end; ++it, ++i) {
|
||||
|
@ -1396,7 +1401,7 @@ namespace smt {
|
|||
SASSERT(d != UINT_MAX);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Divide m by var^d.
|
||||
*/
|
||||
|
@ -1416,19 +1421,19 @@ namespace smt {
|
|||
ptr_buffer<expr> new_args;
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
if (arg == var) {
|
||||
if (idx < d)
|
||||
idx++;
|
||||
else
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
else {
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
if (arg == var) {
|
||||
if (idx < d)
|
||||
idx++;
|
||||
else
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
else {
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
}
|
||||
SASSERT(idx == d);
|
||||
TRACE("factor_bug", tout << "new_args:\n"; for(unsigned i = 0; i < new_args.size(); i++) tout << mk_pp(new_args[i], get_manager()) << "\n";);
|
||||
expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var));
|
||||
expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var));
|
||||
m_nl_new_exprs.push_back(result);
|
||||
TRACE("factor", tout << "result: " << mk_pp(result, get_manager()) << "\n";);
|
||||
return result;
|
||||
|
@ -1442,7 +1447,7 @@ namespace smt {
|
|||
SASSERT(!p.empty());
|
||||
SASSERT(var != 0);
|
||||
unsigned d = get_min_degree(p, var);
|
||||
TRACE("horner_bug", tout << "poly:\n";
|
||||
TRACE("horner_bug", tout << "poly:\n";
|
||||
for (unsigned i = 0; i < p.size(); i++) { if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); } tout << "\n";
|
||||
tout << "var: " << mk_pp(var, get_manager()) << "\n";
|
||||
tout << "min_degree: " << d << "\n";);
|
||||
|
@ -1467,7 +1472,7 @@ namespace smt {
|
|||
// TODO: improve here
|
||||
s = m_util.mk_add(q, s);
|
||||
}
|
||||
|
||||
|
||||
expr * result = s;
|
||||
if (d != 0) {
|
||||
expr * xd = power(var, d);
|
||||
|
@ -1513,9 +1518,9 @@ namespace smt {
|
|||
unsigned nm = UINT_MAX;
|
||||
if (in_monovariate_monomials(p, var, i1, a, n, i2, b, nm)) {
|
||||
CTRACE("in_monovariate_monomials", n == nm,
|
||||
for (unsigned i = 0; i < p.size(); i++) {
|
||||
if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager());
|
||||
}
|
||||
for (unsigned i = 0; i < p.size(); i++) {
|
||||
if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager());
|
||||
}
|
||||
tout << "\n";
|
||||
tout << "var: " << mk_pp(var, get_manager()) << "\n";
|
||||
tout << "i1: " << i1 << "\n";
|
||||
|
@ -1556,7 +1561,7 @@ namespace smt {
|
|||
sbuffer<coeff_expr> rest;
|
||||
unsigned sz = p.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (i != i1 && i != i2)
|
||||
if (i != i1 && i != i2)
|
||||
rest.push_back(p[i]);
|
||||
}
|
||||
if (rest.empty())
|
||||
|
@ -1620,7 +1625,7 @@ namespace smt {
|
|||
|
||||
/**
|
||||
\brief Check whether the polynomial represented by the current row is
|
||||
consistent with respect to the known bound when converted into a
|
||||
consistent with respect to the known bound when converted into a
|
||||
equivalent cross nested form.
|
||||
*/
|
||||
template<typename Ext>
|
||||
|
@ -1630,17 +1635,17 @@ namespace smt {
|
|||
return true;
|
||||
|
||||
TRACE("cross_nested", tout << "problematic...\n";);
|
||||
|
||||
|
||||
/*
|
||||
The method is_cross_nested converts rows back to expressions.
|
||||
The conversion back to expressions may create sort incorrect expressions.
|
||||
This is in some sense ok, since these expressions are temporary, but
|
||||
This is in some sense ok, since these expressions are temporary, but
|
||||
the sort incorrect expressions may generate assertion violations.
|
||||
|
||||
|
||||
Sort incorrect expressions may be created in the following cases:
|
||||
|
||||
|
||||
1) mixed real int rows.
|
||||
|
||||
|
||||
2) int rows that contain non integer coefficients.
|
||||
|
||||
3) int rows that when converted to cross nested form use non integer coefficients.
|
||||
|
@ -1654,10 +1659,10 @@ namespace smt {
|
|||
c) Disable the assertions temporally. This sounds like a big HACK.
|
||||
|
||||
d) Use a different data-structure to represent polynomials in cross-nested form. Disadvantage: code duplication, the data-structure
|
||||
is essentially identical to the ASTs we are using right now.
|
||||
is essentially identical to the ASTs we are using right now.
|
||||
|
||||
e) Disable the test when we cannot create a well-sorted expression.
|
||||
I'm temporally using this solution.
|
||||
I'm temporally using this solution.
|
||||
I implemented the following logic:
|
||||
1) (mixed real int) Disable the test. Most benchmarks do not contain mixed int real variables.
|
||||
2) (int coeffs) I multiply the row by a constant to force it to have only integer coefficients.
|
||||
|
@ -1696,7 +1701,7 @@ namespace smt {
|
|||
svector<theory_var>::const_iterator end = nl_cluster.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
if (!is_base(v))
|
||||
if (!is_base(v))
|
||||
continue;
|
||||
m_stats.m_nl_cross_nested++;
|
||||
row const & r = m_rows[get_var_row(v)];
|
||||
|
@ -1719,8 +1724,8 @@ namespace smt {
|
|||
/**
|
||||
\brief Initialize variable order for grobner basis computation.
|
||||
Make:
|
||||
"quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" >
|
||||
"variables with lower or upper bounds" > "quoted bounded variables" >
|
||||
"quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" >
|
||||
"variables with lower or upper bounds" > "quoted bounded variables" >
|
||||
"bounded variables" > "quoted fixed variables" > "fixed variables"
|
||||
*/
|
||||
template<typename Ext>
|
||||
|
@ -1801,7 +1806,7 @@ namespace smt {
|
|||
}
|
||||
if (!coeff.is_zero())
|
||||
return gb.mk_monomial(coeff, vars.size(), vars.c_ptr());
|
||||
else
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1918,7 +1923,7 @@ namespace smt {
|
|||
derived_bound b(null_theory_var, inf_numeral(0), B_LOWER);
|
||||
dependency2new_bound(d, b);
|
||||
set_conflict(b, ante, "arith_nl");
|
||||
TRACE("non_linear",
|
||||
TRACE("non_linear",
|
||||
for (unsigned i = 0; i < b.m_lits.size(); ++i) {
|
||||
tout << b.m_lits[i] << " ";
|
||||
});
|
||||
|
@ -2027,7 +2032,7 @@ namespace smt {
|
|||
unsigned num1 = m1_sq->get_degree();
|
||||
unsigned num2 = m2_sq->get_degree();
|
||||
unsigned num12 = m1m2->get_degree();
|
||||
if (num1 + num2 != num12 * 2)
|
||||
if (num1 + num2 != num12 * 2)
|
||||
return false;
|
||||
unsigned i1, i2, i12;
|
||||
i1 = i2 = i12 = 0;
|
||||
|
@ -2072,8 +2077,8 @@ namespace smt {
|
|||
*/
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::is_inconsistent2(grobner::equation const * eq, grobner & gb) {
|
||||
// TODO: a possible improvement: create a quotation for (M1 - M2)^2
|
||||
// instead of trying to find it in a specific equation.
|
||||
// TODO: a possible improvement: create a quotation for (M1 - M2)^2
|
||||
// instead of trying to find it in a specific equation.
|
||||
// This approach is more precise, but more expensive
|
||||
// since a new row must be created.
|
||||
buffer<interval> intervals;
|
||||
|
@ -2117,7 +2122,7 @@ namespace smt {
|
|||
continue;
|
||||
// m1, m2, and m1m2 form a perfect square.
|
||||
// check if [0, oo) provides a better lowerbound than adding the intervals of m1, m2 and m1m2;
|
||||
TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n";
|
||||
TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n";
|
||||
gb.display_monomial(tout, *m1); tout << "\n";
|
||||
gb.display_monomial(tout, *m2); tout << "\n";
|
||||
gb.display_monomial(tout, *m1m2); tout << "\n";);
|
||||
|
@ -2131,7 +2136,7 @@ namespace smt {
|
|||
deleted[i] = true;
|
||||
deleted[j] = true;
|
||||
deleted[k] = true;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k < num)
|
||||
|
@ -2184,7 +2189,7 @@ namespace smt {
|
|||
grobner::monomial const * m = eq->get_monomial(i);
|
||||
if (m->get_degree() == 0)
|
||||
k -= m->get_coeff();
|
||||
else
|
||||
else
|
||||
args.push_back(monomial2expr(eq->get_monomial(i), is_int));
|
||||
}
|
||||
context & ctx = get_context();
|
||||
|
@ -2213,7 +2218,7 @@ namespace smt {
|
|||
TRACE("non_linear", tout << "inserted new equation into the tableau\n"; display_var(tout, v););
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Compute Grobner basis, return true if a conflict or new fixed variables were detected.
|
||||
*/
|
||||
|
@ -2227,7 +2232,7 @@ namespace smt {
|
|||
bool warn = false;
|
||||
unsigned next_weight = MAX_DEFAULT_WEIGHT + 1; // next weight using during perturbation phase.
|
||||
ptr_vector<grobner::equation> eqs;
|
||||
|
||||
|
||||
while (true) {
|
||||
TRACE("non_linear_gb", tout << "before:\n"; gb.display(tout););
|
||||
bool r = false;
|
||||
|
@ -2267,7 +2272,7 @@ namespace smt {
|
|||
if (is_inconsistent2(eq, gb))
|
||||
return GB_PROGRESS;
|
||||
}
|
||||
// Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed,
|
||||
// Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed,
|
||||
// then assert bounds for x, and continue
|
||||
gb_result result = GB_FAIL;
|
||||
if (m_params.m_nl_arith_gb_eqs) {
|
||||
|
@ -2277,7 +2282,7 @@ namespace smt {
|
|||
if (!eq->is_linear_combination()) {
|
||||
TRACE("non_linear", tout << "processing new equality:\n"; gb.display_equation(tout, *eq););
|
||||
TRACE("non_linear_bug", tout << "processing new equality:\n"; gb.display_equation(tout, *eq););
|
||||
if (internalize_gb_eq(eq))
|
||||
if (internalize_gb_eq(eq))
|
||||
result = GB_NEW_EQ;
|
||||
}
|
||||
}
|
||||
|
@ -2331,10 +2336,8 @@ namespace smt {
|
|||
bool theory_arith<Ext>::max_min_nl_vars() {
|
||||
var_set already_found;
|
||||
svector<theory_var> vars;
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
for (unsigned i = 0; i < m_nl_monomials.size(); i++) {
|
||||
theory_var v = m_nl_monomials[i];
|
||||
mark_var(v, vars, already_found);
|
||||
expr * n = var2expr(v);
|
||||
SASSERT(is_pure_monomial(n));
|
||||
|
@ -2372,10 +2375,10 @@ namespace smt {
|
|||
IF_VERBOSE(3, verbose_stream() << "Max. non linear arithmetic rounds. Increase threshold using NL_ARITH_ROUNDS=<limit>\n";);
|
||||
return FC_GIVEUP;
|
||||
}
|
||||
|
||||
|
||||
get_context().push_trail(value_trail<context, unsigned>(m_nl_rounds));
|
||||
m_nl_rounds++;
|
||||
|
||||
|
||||
elim_quasi_base_rows();
|
||||
move_non_base_vars_to_bounds();
|
||||
TRACE("non_linear", tout << "processing non linear constraints...\n"; get_context().display(tout););
|
||||
|
@ -2384,8 +2387,8 @@ namespace smt {
|
|||
failed();
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
|
||||
if (!max_min_nl_vars())
|
||||
|
||||
if (!max_min_nl_vars())
|
||||
return FC_CONTINUE;
|
||||
|
||||
if (check_monomial_assignments()) {
|
||||
|
@ -2409,20 +2412,20 @@ namespace smt {
|
|||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!is_cross_nested_consistent(vars))
|
||||
if (!is_cross_nested_consistent(vars))
|
||||
progress = true;
|
||||
break;
|
||||
case 2:
|
||||
if (m_params.m_nl_arith_gb) {
|
||||
switch(compute_grobner(vars)) {
|
||||
case GB_PROGRESS:
|
||||
case GB_PROGRESS:
|
||||
progress = true;
|
||||
break;
|
||||
case GB_NEW_EQ:
|
||||
case GB_NEW_EQ:
|
||||
progress = true;
|
||||
propagate_core();
|
||||
break;
|
||||
case GB_FAIL:
|
||||
case GB_FAIL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ Revision History:
|
|||
#include"theory_fpa.h"
|
||||
#include"theory_bv.h"
|
||||
#include"smt_model_generator.h"
|
||||
#include"bv2fpa_converter.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
@ -116,15 +117,15 @@ namespace smt {
|
|||
|
||||
SASSERT(m_trail_stack.get_num_scopes() == 0);
|
||||
SASSERT(m_conversions.empty());
|
||||
SASSERT(m_is_added_to_model.empty());
|
||||
}
|
||||
SASSERT(m_is_added_to_model.empty());
|
||||
}
|
||||
void theory_fpa::init(context * ctx) {
|
||||
smt::theory::init(ctx);
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector<expr> & values) {
|
||||
TRACE("t_fpa_detail",
|
||||
TRACE("t_fpa_detail",
|
||||
ast_manager & m = m_th.get_manager();
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;);
|
||||
|
@ -201,7 +202,7 @@ namespace smt {
|
|||
app * theory_fpa::fpa_rm_value_proc::mk_value(model_generator & mg, ptr_vector<expr> & values) {
|
||||
SASSERT(values.size() == 1);
|
||||
|
||||
TRACE("t_fpa_detail",
|
||||
TRACE("t_fpa_detail",
|
||||
ast_manager & m = m_th.get_manager();
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;);
|
||||
|
@ -235,12 +236,12 @@ namespace smt {
|
|||
app_ref res(m);
|
||||
|
||||
if (m_fpa_util.is_fp(e)) {
|
||||
expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) };
|
||||
expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) };
|
||||
res = m_bv_util.mk_concat(3, cargs);
|
||||
m_th_rw((expr_ref&)res);
|
||||
}
|
||||
else {
|
||||
sort * es = m.get_sort(e);
|
||||
sort * es = m.get_sort(e);
|
||||
|
||||
sort_ref bv_srt(m);
|
||||
if (m_converter.is_rm(es))
|
||||
|
@ -264,7 +265,7 @@ namespace smt {
|
|||
SASSERT(!m_fpa_util.is_fp(e));
|
||||
SASSERT(m_bv_util.is_bv(e));
|
||||
SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s));
|
||||
ast_manager & m = get_manager();
|
||||
ast_manager & m = get_manager();
|
||||
app_ref res(m);
|
||||
|
||||
unsigned bv_sz = m_bv_util.get_bv_size(e);
|
||||
|
@ -285,7 +286,7 @@ namespace smt {
|
|||
m_bv_util.mk_extract(bv_sz - 2, sbits - 1, e),
|
||||
m_bv_util.mk_extract(sbits - 2, 0, e));
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -312,7 +313,7 @@ namespace smt {
|
|||
TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << std::endl;
|
||||
tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << std::endl;);
|
||||
|
||||
if (m_fpa_util.is_rm(e)) {
|
||||
if (m_fpa_util.is_rm(e)) {
|
||||
SASSERT(m_fpa_util.is_bv2rm(e_conv));
|
||||
expr_ref bv_rm(m);
|
||||
m_th_rw(to_app(e_conv)->get_arg(0), bv_rm);
|
||||
|
@ -329,7 +330,7 @@ namespace smt {
|
|||
}
|
||||
else
|
||||
UNREACHABLE();
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -362,7 +363,7 @@ namespace smt {
|
|||
res = convert_atom(e);
|
||||
else if (m_fpa_util.is_float(e) || m_fpa_util.is_rm(e))
|
||||
res = convert_term(e);
|
||||
else
|
||||
else
|
||||
res = convert_conversion_term(e);
|
||||
|
||||
TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl;
|
||||
|
@ -448,7 +449,7 @@ namespace smt {
|
|||
TRACE("t_fpa_internalize", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";);
|
||||
SASSERT(term->get_family_id() == get_family_id());
|
||||
SASSERT(!get_context().e_internalized(term));
|
||||
|
||||
|
||||
ast_manager & m = get_manager();
|
||||
context & ctx = get_context();
|
||||
|
||||
|
@ -494,7 +495,7 @@ namespace smt {
|
|||
SASSERT(n->get_owner()->get_decl()->get_range() == s);
|
||||
|
||||
ast_manager & m = get_manager();
|
||||
context & ctx = get_context();
|
||||
context & ctx = get_context();
|
||||
app_ref owner(n->get_owner(), m);
|
||||
|
||||
if (!is_attached_to_var(n)) {
|
||||
|
@ -510,7 +511,7 @@ namespace smt {
|
|||
assert_cnstr(valid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!ctx.relevancy())
|
||||
relevant_eh(owner);
|
||||
}
|
||||
|
@ -600,7 +601,7 @@ namespace smt {
|
|||
xe_eq_ye = m.mk_eq(xe, ye);
|
||||
not_xe_eq_ye = m.mk_not(xe_eq_ye);
|
||||
c_eq_iff = m.mk_iff(not_xe_eq_ye, c);
|
||||
assert_cnstr(c_eq_iff);
|
||||
assert_cnstr(c_eq_iff);
|
||||
assert_cnstr(mk_side_conditions());
|
||||
|
||||
return;
|
||||
|
@ -689,10 +690,10 @@ namespace smt {
|
|||
pop_scope_eh(m_trail_stack.get_num_scopes());
|
||||
m_converter.reset();
|
||||
m_rw.reset();
|
||||
m_th_rw.reset();
|
||||
m_trail_stack.pop_scope(m_trail_stack.get_num_scopes());
|
||||
m_th_rw.reset();
|
||||
m_trail_stack.pop_scope(m_trail_stack.get_num_scopes());
|
||||
if (m_factory) {
|
||||
dealloc(m_factory);
|
||||
dealloc(m_factory);
|
||||
m_factory = 0;
|
||||
}
|
||||
ast_manager & m = get_manager();
|
||||
|
@ -712,20 +713,6 @@ namespace smt {
|
|||
ast_manager & m = get_manager();
|
||||
m_factory = alloc(fpa_value_factory, m, get_family_id());
|
||||
mg.register_factory(m_factory);
|
||||
|
||||
fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf();
|
||||
for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin();
|
||||
it != uf2bvuf.end();
|
||||
it++) {
|
||||
mg.hide(it->m_value);
|
||||
}
|
||||
fpa2bv_converter::special_t const & specials = m_converter.get_min_max_specials();
|
||||
for (fpa2bv_converter::special_t::iterator it = specials.begin();
|
||||
it != specials.end();
|
||||
it++) {
|
||||
mg.hide(it->m_value.first->get_decl());
|
||||
mg.hide(it->m_value.second->get_decl());
|
||||
}
|
||||
}
|
||||
|
||||
model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) {
|
||||
|
@ -811,8 +798,34 @@ namespace smt {
|
|||
return res;
|
||||
}
|
||||
|
||||
void theory_fpa::finalize_model(model_generator & mg) {}
|
||||
|
||||
void theory_fpa::finalize_model(model_generator & mg) {
|
||||
ast_manager & m = get_manager();
|
||||
proto_model & mdl = mg.get_model();
|
||||
proto_model new_model(m);
|
||||
|
||||
bv2fpa_converter bv2fp(m, m_converter);
|
||||
|
||||
obj_hashtable<func_decl> seen;
|
||||
bv2fp.convert_min_max_specials(&mdl, &new_model, seen);
|
||||
bv2fp.convert_uf2bvuf(&mdl, &new_model, seen);
|
||||
|
||||
for (obj_hashtable<func_decl>::iterator it = seen.begin();
|
||||
it != seen.end();
|
||||
it++)
|
||||
mdl.unregister_decl(*it);
|
||||
|
||||
for (unsigned i = 0; i < new_model.get_num_constants(); i++) {
|
||||
func_decl * f = new_model.get_constant(i);
|
||||
mdl.register_decl(f, new_model.get_const_interp(f));
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < new_model.get_num_functions(); i++) {
|
||||
func_decl * f = new_model.get_function(i);
|
||||
func_interp * fi = new_model.get_func_interp(f)->copy();
|
||||
mdl.register_decl(f, fi);
|
||||
}
|
||||
}
|
||||
|
||||
void theory_fpa::display(std::ostream & out) const
|
||||
{
|
||||
ast_manager & m = get_manager();
|
||||
|
@ -862,8 +875,8 @@ namespace smt {
|
|||
}
|
||||
|
||||
bool theory_fpa::include_func_interp(func_decl * f) {
|
||||
TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;);
|
||||
|
||||
TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;);
|
||||
|
||||
if (f->get_family_id() == get_family_id()) {
|
||||
bool include =
|
||||
m_fpa_util.is_min_unspecified(f) ||
|
||||
|
|
|
@ -519,7 +519,7 @@ namespace smt {
|
|||
c->m_compilation_threshold = th;
|
||||
IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threhshold to " << th << ")\n";);
|
||||
TRACE("pb", tout << "compilation threshold: " << th << "\n";);
|
||||
compile_ineq(*c);
|
||||
//compile_ineq(*c);
|
||||
}
|
||||
else {
|
||||
c->m_compilation_threshold = UINT_MAX;
|
||||
|
|
|
@ -29,6 +29,7 @@ Revision History:
|
|||
#include "extension_model_converter.h"
|
||||
#include "var_subst.h"
|
||||
#include "ast_util.h"
|
||||
#include "fd_rewriter.h"
|
||||
|
||||
|
||||
class dt2bv_tactic : public tactic {
|
||||
|
@ -39,173 +40,8 @@ class dt2bv_tactic : public tactic {
|
|||
bv_util m_bv;
|
||||
obj_hashtable<sort> m_fd_sorts;
|
||||
obj_hashtable<sort> m_non_fd_sorts;
|
||||
expr_ref_vector m_bounds;
|
||||
ref<extension_model_converter> m_ext;
|
||||
ref<filter_model_converter> m_filter;
|
||||
unsigned m_num_translated;
|
||||
|
||||
struct rw_cfg : public default_rewriter_cfg {
|
||||
dt2bv_tactic& m_t;
|
||||
ast_manager& m;
|
||||
params_ref m_params;
|
||||
obj_map<expr, expr*> m_cache;
|
||||
expr_ref_vector m_trail;
|
||||
|
||||
rw_cfg(dt2bv_tactic& t, ast_manager & m, params_ref const & p) :
|
||||
m_t(t),
|
||||
m(m),
|
||||
m_params(p),
|
||||
m_trail(m)
|
||||
{}
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
expr_ref a0(m), a1(m);
|
||||
expr_ref_vector _args(m);
|
||||
if (m.is_eq(f) && reduce_arg(args[0], a0) && reduce_arg(args[1], a1)) {
|
||||
result = m.mk_eq(a0, a1);
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (m.is_distinct(f) && reduce_args(num, args, _args)) {
|
||||
result = m.mk_distinct(_args.size(), _args.c_ptr());
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (m_t.m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) {
|
||||
unsigned idx = m_t.m_dt.get_recognizer_constructor_idx(f);
|
||||
a1 = m_t.m_bv.mk_numeral(rational(idx), get_sort(a0));
|
||||
result = m.mk_eq(a0, a1);
|
||||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
bool reduce_args(unsigned sz, expr*const* as, expr_ref_vector& result) {
|
||||
expr_ref tmp(m);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
if (!reduce_arg(as[i], tmp)) return false;
|
||||
result.push_back(tmp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reduce_arg(expr* a, expr_ref& result) {
|
||||
expr* b;
|
||||
if (m_cache.find(a, b)) {
|
||||
result = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
sort* s = get_sort(a);
|
||||
if (!m_t.m_fd_sorts.contains(s)) {
|
||||
return false;
|
||||
}
|
||||
unsigned bv_size = get_bv_size(s);
|
||||
|
||||
if (is_var(a)) {
|
||||
result = m.mk_var(to_var(a)->get_idx(), m_t.m_bv.mk_sort(bv_size));
|
||||
return true;
|
||||
}
|
||||
SASSERT(is_app(a));
|
||||
func_decl* f = to_app(a)->get_decl();
|
||||
if (m_t.m_dt.is_constructor(f)) {
|
||||
unsigned idx = m_t.m_dt.get_constructor_idx(f);
|
||||
result = m_t.m_bv.mk_numeral(idx, bv_size);
|
||||
}
|
||||
else if (is_uninterp_const(a)) {
|
||||
// create a fresh variable, add bounds constraints for it.
|
||||
unsigned nc = m_t.m_dt.get_datatype_num_constructors(s);
|
||||
result = m.mk_fresh_const(f->get_name().str().c_str(), m_t.m_bv.mk_sort(bv_size));
|
||||
if (!is_power_of_two(nc)) {
|
||||
m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc, bv_size)));
|
||||
}
|
||||
expr_ref f_def(m);
|
||||
ptr_vector<func_decl> const& cs = *m_t.m_dt.get_datatype_constructors(s);
|
||||
f_def = m.mk_const(cs[nc-1]);
|
||||
for (unsigned i = nc - 1; i > 0; ) {
|
||||
--i;
|
||||
f_def = m.mk_ite(m.mk_eq(result, m_t.m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def);
|
||||
}
|
||||
// update model converters.
|
||||
m_t.m_ext->insert(f, f_def);
|
||||
m_t.m_filter->insert(to_app(result)->get_decl());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
m_cache.insert(a, result);
|
||||
++m_t.m_num_translated;
|
||||
return true;
|
||||
}
|
||||
|
||||
ptr_buffer<sort> m_sorts;
|
||||
|
||||
bool reduce_quantifier(
|
||||
quantifier * q,
|
||||
expr * old_body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
m_sorts.reset();
|
||||
expr_ref_vector bounds(m);
|
||||
bool found = false;
|
||||
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
|
||||
sort* s = q->get_decl_sort(i);
|
||||
if (m_t.m_fd_sorts.contains(s)) {
|
||||
unsigned bv_size = get_bv_size(s);
|
||||
m_sorts.push_back(m_t.m_bv.mk_sort(bv_size));
|
||||
unsigned nc = m_t.m_dt.get_datatype_num_constructors(s);
|
||||
if (!is_power_of_two(nc)) {
|
||||
bounds.push_back(m_t.m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_t.m_bv.mk_numeral(nc, bv_size)));
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
else {
|
||||
m_sorts.push_back(s);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
expr_ref new_body_ref(old_body, m), tmp(m);
|
||||
if (!bounds.empty()) {
|
||||
if (q->is_forall()) {
|
||||
new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref);
|
||||
}
|
||||
else {
|
||||
bounds.push_back(new_body_ref);
|
||||
new_body_ref = mk_and(bounds);
|
||||
}
|
||||
}
|
||||
result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref,
|
||||
q->get_weight(), q->get_qid(), q->get_skid(),
|
||||
q->get_num_patterns(), new_patterns,
|
||||
q->get_num_no_patterns(), new_no_patterns);
|
||||
result_pr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned get_bv_size(sort* s) {
|
||||
unsigned nc = m_t.m_dt.get_datatype_num_constructors(s);
|
||||
unsigned bv_size = 1;
|
||||
while ((unsigned)(1 << bv_size) < nc) {
|
||||
++bv_size;
|
||||
}
|
||||
return bv_size;
|
||||
}
|
||||
};
|
||||
|
||||
struct rw : public rewriter_tpl<rw_cfg> {
|
||||
rw_cfg m_cfg;
|
||||
|
||||
rw(dt2bv_tactic& t, ast_manager & m, params_ref const & p) :
|
||||
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(t, m, p) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
obj_map<func_decl, func_decl*>* m_translate;
|
||||
|
||||
|
||||
bool is_fd(expr* a) { return is_fd(get_sort(a)); }
|
||||
bool is_fd(sort* a) { return m_dt.is_enum_sort(a); }
|
||||
|
@ -251,13 +87,23 @@ class dt2bv_tactic : public tactic {
|
|||
void operator()(quantifier* q) {}
|
||||
};
|
||||
|
||||
struct sort_pred : public i_sort_pred {
|
||||
dt2bv_tactic& m_t;
|
||||
sort_pred(dt2bv_tactic& t): m_t(t) {}
|
||||
virtual ~sort_pred() {}
|
||||
virtual bool operator()(sort* s) {
|
||||
return m_t.m_fd_sorts.contains(s);
|
||||
}
|
||||
};
|
||||
|
||||
sort_pred m_is_fd;
|
||||
public:
|
||||
|
||||
dt2bv_tactic(ast_manager& m, params_ref const& p):
|
||||
m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m) {}
|
||||
dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map<func_decl, func_decl*>* tr):
|
||||
m(m), m_params(p), m_dt(m), m_bv(m), m_translate(tr), m_is_fd(*this) {}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(dt2bv_tactic, m, m_params);
|
||||
return alloc(dt2bv_tactic, m, m_params, 0);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
|
@ -285,26 +131,43 @@ public:
|
|||
m_fd_sorts.remove(*it);
|
||||
}
|
||||
if (!m_fd_sorts.empty()) {
|
||||
m_bounds.reset();
|
||||
m_num_translated = 0;
|
||||
m_ext = alloc(extension_model_converter, m);
|
||||
m_filter = alloc(filter_model_converter, m);
|
||||
scoped_ptr<rw> r = alloc(rw, *this, m, m_params);
|
||||
ref<extension_model_converter> ext = alloc(extension_model_converter, m);
|
||||
ref<filter_model_converter> filter = alloc(filter_model_converter, m);
|
||||
fd_rewriter rw(m, m_params);
|
||||
rw.set_is_fd(&m_is_fd);
|
||||
expr_ref new_curr(m);
|
||||
proof_ref new_pr(m);
|
||||
for (unsigned idx = 0; idx < size; idx++) {
|
||||
(*r)(g->form(idx), new_curr, new_pr);
|
||||
rw(g->form(idx), new_curr, new_pr);
|
||||
if (produce_proofs) {
|
||||
proof * pr = g->pr(idx);
|
||||
new_pr = m.mk_modus_ponens(pr, new_pr);
|
||||
}
|
||||
g->update(idx, new_curr, new_pr, g->dep(idx));
|
||||
}
|
||||
for (unsigned i = 0; i < m_bounds.size(); ++i) {
|
||||
g->assert_expr(m_bounds[i].get());
|
||||
expr_ref_vector bounds(m);
|
||||
rw.flush_side_constraints(bounds);
|
||||
for (unsigned i = 0; i < bounds.size(); ++i) {
|
||||
g->assert_expr(bounds[i].get());
|
||||
}
|
||||
mc = concat(m_filter.get(), m_ext.get());
|
||||
report_tactic_progress(":fd-num-translated", m_num_translated);
|
||||
{
|
||||
obj_map<func_decl, func_decl*>::iterator it = rw.enum2bv().begin(), end = rw.enum2bv().end();
|
||||
for (; it != end; ++it) {
|
||||
filter->insert(it->m_value);
|
||||
if (m_translate) {
|
||||
m_translate->insert(it->m_key, it->m_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
obj_map<func_decl, expr*>::iterator it = rw.enum2def().begin(), end = rw.enum2def().end();
|
||||
for (; it != end; ++it) {
|
||||
ext->insert(it->m_key, it->m_value);
|
||||
}
|
||||
}
|
||||
|
||||
mc = concat(filter.get(), ext.get());
|
||||
report_tactic_progress(":fd-num-translated", rw.num_translated());
|
||||
}
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
|
@ -315,11 +178,10 @@ public:
|
|||
virtual void cleanup() {
|
||||
m_fd_sorts.reset();
|
||||
m_non_fd_sorts.reset();
|
||||
m_bounds.reset();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p) {
|
||||
return alloc(dt2bv_tactic, m, p);
|
||||
tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map<func_decl, func_decl*>* tr) {
|
||||
return alloc(dt2bv_tactic, m, p, tr);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,11 @@ Revision History:
|
|||
#define DT2BV_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
#include"obj_hashtable.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map<func_decl, func_decl*>* tr = 0);
|
||||
|
||||
/*
|
||||
ADD_TACTIC("dt2bv", "eliminate finite domain data-types. Replace by bit-vectors.", "mk_dt2bv_tactic(m, p)")
|
||||
|
|
|
@ -71,7 +71,7 @@ void extension_model_converter::operator()(model_ref & md, unsigned goal_idx) {
|
|||
|
||||
void extension_model_converter::insert(func_decl * v, expr * def) {
|
||||
m_vars.push_back(v);
|
||||
m_defs.push_back(def);
|
||||
m_defs.push_back(def);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,448 +22,50 @@ Notes:
|
|||
|
||||
void fpa2bv_model_converter::display(std::ostream & out) {
|
||||
out << "(fpa2bv-model-converter";
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
|
||||
it != m_const2bv.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
|
||||
}
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
|
||||
it != m_rm_const2bv.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
|
||||
}
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
|
||||
it != m_uf2bvuf.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
|
||||
}
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
const symbol & n = it->m_key->get_name();
|
||||
out << "\n (" << n << " ";
|
||||
unsigned indent = n.size() + 4;
|
||||
out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " <<
|
||||
mk_ismt2_pp(it->m_value.second, m, indent) << ")";
|
||||
}
|
||||
m_bv2fp->display(out);
|
||||
out << ")";
|
||||
}
|
||||
|
||||
model_converter * fpa2bv_model_converter::translate(ast_translation & translator) {
|
||||
fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to());
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
|
||||
it != m_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * k = translator(it->m_key);
|
||||
expr * v = translator(it->m_value);
|
||||
res->m_const2bv.insert(k, v);
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v);
|
||||
}
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
|
||||
it != m_rm_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * k = translator(it->m_key);
|
||||
expr * v = translator(it->m_value);
|
||||
res->m_rm_const2bv.insert(k, v);
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v);
|
||||
}
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
|
||||
it != m_uf2bvuf.end();
|
||||
it++) {
|
||||
func_decl * k = translator(it->m_key);
|
||||
func_decl * v = translator(it->m_value);
|
||||
res->m_uf2bvuf.insert(k, v);
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v);
|
||||
}
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
func_decl * k = translator(it->m_key);
|
||||
app * v1 = translator(it->m_value.first);
|
||||
app * v2 = translator(it->m_value.second);
|
||||
res->m_specials.insert(k, std::pair<app*, app*>(v1, v2));
|
||||
translator.to().inc_ref(k);
|
||||
translator.to().inc_ref(v1);
|
||||
translator.to().inc_ref(v2);
|
||||
}
|
||||
res->m_bv2fp = m_bv2fp->translate(translator);
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) {
|
||||
unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager();
|
||||
unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager();
|
||||
|
||||
expr_ref res(m);
|
||||
mpf fp_val;
|
||||
|
||||
unsigned ebits = m_fpa_util.get_ebits(s);
|
||||
unsigned sbits = m_fpa_util.get_sbits(s);
|
||||
|
||||
unsigned sgn_sz = 1;
|
||||
unsigned exp_sz = ebits;
|
||||
unsigned sig_sz = sbits - 1;
|
||||
|
||||
rational sgn_q(0), sig_q(0), exp_q(0);
|
||||
|
||||
if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz);
|
||||
if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz);
|
||||
if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz);
|
||||
|
||||
// un-bias exponent
|
||||
rational exp_unbiased_q;
|
||||
exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 1);
|
||||
|
||||
mpz sig_z; mpf_exp_t exp_z;
|
||||
mpzm.set(sig_z, sig_q.to_mpq().numerator());
|
||||
exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator());
|
||||
|
||||
m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z);
|
||||
|
||||
mpzm.del(sig_z);
|
||||
|
||||
res = m_fpa_util.mk_value(fp_val);
|
||||
|
||||
TRACE("fpa2bv_mc", tout << "[" << mk_ismt2_pp(sgn, m) <<
|
||||
" " << mk_ismt2_pp(exp, m) <<
|
||||
" " << mk_ismt2_pp(sig, m) << "] == " <<
|
||||
mk_ismt2_pp(res, m) << std::endl;);
|
||||
m_fpa_util.fm().del(fp_val);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * bv) {
|
||||
SASSERT(m_bv_util.is_bv(bv));
|
||||
|
||||
unsigned ebits = m_fpa_util.get_ebits(s);
|
||||
unsigned sbits = m_fpa_util.get_sbits(s);
|
||||
unsigned bv_sz = sbits + ebits;
|
||||
|
||||
expr_ref sgn(m), exp(m), sig(m);
|
||||
sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv);
|
||||
exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv);
|
||||
sig = m_bv_util.mk_extract(sbits - 2, 0, bv);
|
||||
|
||||
expr_ref v_sgn(m), v_exp(m), v_sig(m);
|
||||
bv_mdl->eval(sgn, v_sgn);
|
||||
bv_mdl->eval(exp, v_exp);
|
||||
bv_mdl->eval(sig, v_sig);
|
||||
|
||||
return convert_bv2fp(s, v_sgn, v_exp, v_sig);
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_model_converter::convert_bv2rm(expr * bv_rm) {
|
||||
expr_ref res(m);
|
||||
rational bv_val(0);
|
||||
unsigned sz = 0;
|
||||
|
||||
if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) {
|
||||
SASSERT(bv_val.is_uint64());
|
||||
switch (bv_val.get_uint64()) {
|
||||
case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break;
|
||||
case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break;
|
||||
case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break;
|
||||
case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break;
|
||||
case BV_RM_TO_ZERO:
|
||||
default: res = m_fpa_util.mk_round_toward_zero();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, expr * val) {
|
||||
expr_ref res(m);
|
||||
expr_ref eval_v(m);
|
||||
|
||||
if (val && bv_mdl->eval(val, eval_v, true))
|
||||
res = convert_bv2rm(eval_v);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_model_converter::rebuild_floats(model * bv_mdl, sort * s, expr * e) {
|
||||
expr_ref result(m);
|
||||
TRACE("fpa2bv_mc", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for " << mk_ismt2_pp(e, m) << std::endl;);
|
||||
|
||||
if (m_fpa_util.is_float(s)) {
|
||||
if (m_fpa_util.is_numeral(e)) {
|
||||
result = e;
|
||||
}
|
||||
else {
|
||||
SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s)));
|
||||
result = convert_bv2fp(bv_mdl, s, e);
|
||||
}
|
||||
}
|
||||
else if (m_fpa_util.is_rm(s)) {
|
||||
if (m_fpa_util.is_rm_numeral(e)) {
|
||||
result = e;
|
||||
}
|
||||
else {
|
||||
SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3);
|
||||
result = convert_bv2rm(bv_mdl, e);
|
||||
}
|
||||
}
|
||||
else if (is_app(e)) {
|
||||
app * a = to_app(e);
|
||||
expr_ref_vector new_args(m);
|
||||
for (unsigned i = 0; i < a->get_num_args(); i++)
|
||||
new_args.push_back(rebuild_floats(bv_mdl, a->get_decl()->get_domain()[i], a->get_arg(i)));
|
||||
result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) {
|
||||
SASSERT(f->get_arity() == 0);
|
||||
array_util arr_util(m);
|
||||
|
||||
array_model am(m);
|
||||
sort_ref_vector array_domain(m);
|
||||
unsigned arity = f->get_range()->get_num_parameters()-1;
|
||||
|
||||
expr_ref as_arr_mdl(m);
|
||||
as_arr_mdl = bv_mdl->get_const_interp(bv_f);
|
||||
if (as_arr_mdl == 0) return am;
|
||||
TRACE("fpa2bv_mc", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;);
|
||||
SASSERT(arr_util.is_as_array(as_arr_mdl));
|
||||
for (unsigned i = 0; i < arity; i++)
|
||||
array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast()));
|
||||
sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast());
|
||||
|
||||
bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl));
|
||||
|
||||
am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng);
|
||||
am.new_float_fi = convert_func_interp(am.new_float_fd, bv_f, bv_mdl);
|
||||
am.bv_fd = bv_f;
|
||||
am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd);
|
||||
return am;
|
||||
}
|
||||
|
||||
func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) {
|
||||
SASSERT(f->get_arity() > 0);
|
||||
func_interp * result = 0;
|
||||
sort * rng = f->get_range();
|
||||
sort * const * dmn = f->get_domain();
|
||||
|
||||
unsigned arity = bv_f->get_arity();
|
||||
func_interp * bv_fi = bv_mdl->get_func_interp(bv_f);
|
||||
|
||||
if (bv_fi != 0) {
|
||||
fpa_rewriter rw(m);
|
||||
expr_ref ai(m);
|
||||
result = alloc(func_interp, m, arity);
|
||||
|
||||
for (unsigned i = 0; i < bv_fi->num_entries(); i++) {
|
||||
func_entry const * bv_fe = bv_fi->get_entry(i);
|
||||
expr * const * bv_args = bv_fe->get_args();
|
||||
expr_ref_buffer new_args(m);
|
||||
|
||||
for (unsigned j = 0; j < arity; j++) {
|
||||
sort * ft_dj = dmn[j];
|
||||
expr * bv_aj = bv_args[j];
|
||||
ai = rebuild_floats(bv_mdl, ft_dj, bv_aj);
|
||||
m_th_rw(ai);
|
||||
new_args.push_back(ai);
|
||||
}
|
||||
|
||||
expr_ref bv_fres(m), ft_fres(m);
|
||||
bv_fres = bv_fe->get_result();
|
||||
ft_fres = rebuild_floats(bv_mdl, rng, bv_fres);
|
||||
m_th_rw(ft_fres);
|
||||
result->insert_new_entry(new_args.c_ptr(), ft_fres);
|
||||
}
|
||||
|
||||
expr_ref bv_els(m), ft_els(m);
|
||||
bv_els = bv_fi->get_else();
|
||||
ft_els = rebuild_floats(bv_mdl, rng, bv_els);
|
||||
m_th_rw(ft_els);
|
||||
result->set_else(ft_els);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) {
|
||||
TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl;
|
||||
for (unsigned i = 0; i < bv_mdl->get_num_constants(); i++)
|
||||
tout << bv_mdl->get_constant(i)->get_name() << " --> " <<
|
||||
mk_ismt2_pp(bv_mdl->get_const_interp(bv_mdl->get_constant(i)), m) << std::endl;
|
||||
for (unsigned i = 0; i < bv_mdl->get_num_functions(); i++) {
|
||||
func_decl * f = bv_mdl->get_function(i);
|
||||
tout << f->get_name() << "(...) := " << std::endl;
|
||||
func_interp * fi = bv_mdl->get_func_interp(f);
|
||||
for (unsigned j = 0; j < fi->num_entries(); j++) {
|
||||
func_entry const * fe = fi->get_entry(j);
|
||||
for (unsigned k = 0; k < f->get_arity(); k++) {
|
||||
tout << mk_ismt2_pp(fe->get_arg(k), m) << " ";
|
||||
}
|
||||
tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl;
|
||||
}
|
||||
tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl;
|
||||
});
|
||||
|
||||
void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) {
|
||||
obj_hashtable<func_decl> seen;
|
||||
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
func_decl * f = it->m_key;
|
||||
expr_ref pzero(m), nzero(m);
|
||||
pzero = m_fpa_util.mk_pzero(f->get_range());
|
||||
nzero = m_fpa_util.mk_nzero(f->get_range());
|
||||
|
||||
expr_ref pn(m), np(m);
|
||||
bv_mdl->eval(it->m_value.first, pn, true);
|
||||
bv_mdl->eval(it->m_value.second, np, true);
|
||||
seen.insert(it->m_value.first->get_decl());
|
||||
seen.insert(it->m_value.second->get_decl());
|
||||
|
||||
rational pn_num, np_num;
|
||||
unsigned bv_sz;
|
||||
m_bv_util.is_numeral(pn, pn_num, bv_sz);
|
||||
m_bv_util.is_numeral(np, np_num, bv_sz);
|
||||
|
||||
func_interp * flt_fi = alloc(func_interp, m, f->get_arity());
|
||||
expr * pn_args[2] = { pzero, nzero };
|
||||
if (pn != np) flt_fi->insert_new_entry(pn_args, (pn_num.is_one() ? nzero : pzero));
|
||||
flt_fi->set_else(np_num.is_one() ? nzero : pzero);
|
||||
|
||||
float_mdl->register_decl(f, flt_fi);
|
||||
TRACE("fpa2bv_mc", tout << "fp.min/fp.max special: " << std::endl <<
|
||||
mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;);
|
||||
}
|
||||
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
|
||||
it != m_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * var = it->m_key;
|
||||
app * val = to_app(it->m_value);
|
||||
SASSERT(m_fpa_util.is_float(var->get_range()));
|
||||
SASSERT(var->get_range()->get_num_parameters() == 2);
|
||||
|
||||
expr_ref sgn(m), sig(m), exp(m);
|
||||
bv_mdl->eval(val->get_arg(0), sgn, true);
|
||||
bv_mdl->eval(val->get_arg(1), exp, true);
|
||||
bv_mdl->eval(val->get_arg(2), sig, true);
|
||||
|
||||
SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP));
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0);
|
||||
SASSERT(to_app(val->get_arg(1))->get_decl()->get_arity() == 0);
|
||||
SASSERT(to_app(val->get_arg(2))->get_decl()->get_arity() == 0);
|
||||
seen.insert(to_app(val->get_arg(0))->get_decl());
|
||||
seen.insert(to_app(val->get_arg(1))->get_decl());
|
||||
seen.insert(to_app(val->get_arg(2))->get_decl());
|
||||
#else
|
||||
SASSERT(a->get_arg(0)->get_kind() == OP_EXTRACT);
|
||||
SASSERT(to_app(a->get_arg(0))->get_arg(0)->get_kind() == OP_EXTRACT);
|
||||
seen.insert(to_app(to_app(val->get_arg(0))->get_arg(0))->get_decl());
|
||||
#endif
|
||||
|
||||
if (!sgn && !sig && !exp)
|
||||
continue;
|
||||
|
||||
expr_ref cv(m);
|
||||
cv = convert_bv2fp(var->get_range(), sgn, exp, sig);
|
||||
float_mdl->register_decl(var, cv);
|
||||
|
||||
TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;);
|
||||
}
|
||||
|
||||
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
|
||||
it != m_rm_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
func_decl * var = it->m_key;
|
||||
SASSERT(m_fpa_util.is_rm(var->get_range()));
|
||||
expr * val = it->m_value;
|
||||
SASSERT(m_fpa_util.is_bv2rm(val));
|
||||
expr * bvval = to_app(val)->get_arg(0);
|
||||
expr_ref fv(m);
|
||||
fv = convert_bv2rm(bv_mdl, bvval);
|
||||
TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;);
|
||||
float_mdl->register_decl(var, fv);
|
||||
seen.insert(to_app(bvval)->get_decl());
|
||||
}
|
||||
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
|
||||
it != m_uf2bvuf.end();
|
||||
it++) {
|
||||
seen.insert(it->m_value);
|
||||
|
||||
func_decl * f = it->m_key;
|
||||
if (f->get_arity() == 0)
|
||||
{
|
||||
array_util au(m);
|
||||
if (au.is_array(f->get_range())) {
|
||||
array_model am = convert_array_func_interp(f, it->m_value, bv_mdl);
|
||||
if (am.new_float_fd) float_mdl->register_decl(am.new_float_fd, am.new_float_fi);
|
||||
if (am.result) float_mdl->register_decl(f, am.result);
|
||||
if (am.bv_fd) seen.insert(am.bv_fd);
|
||||
}
|
||||
else {
|
||||
// Just keep.
|
||||
SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range()));
|
||||
expr_ref val(m);
|
||||
bv_mdl->eval(it->m_value, val);
|
||||
if (val) float_mdl->register_decl(f, val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl);
|
||||
if (fmv) float_mdl->register_decl(f, fmv);
|
||||
}
|
||||
}
|
||||
|
||||
m_bv2fp->convert_consts(mc, float_mdl, seen);
|
||||
m_bv2fp->convert_rm_consts(mc, float_mdl, seen);
|
||||
m_bv2fp->convert_min_max_specials(mc, float_mdl, seen);
|
||||
m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen);
|
||||
|
||||
// Keep all the non-float constants.
|
||||
unsigned sz = bv_mdl->get_num_constants();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
{
|
||||
func_decl * c = bv_mdl->get_constant(i);
|
||||
unsigned sz = mc->get_num_constants();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
func_decl * c = mc->get_constant(i);
|
||||
if (!seen.contains(c))
|
||||
float_mdl->register_decl(c, bv_mdl->get_const_interp(c));
|
||||
float_mdl->register_decl(c, mc->get_const_interp(c));
|
||||
}
|
||||
|
||||
|
||||
// And keep everything else
|
||||
sz = bv_mdl->get_num_functions();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
{
|
||||
func_decl * f = bv_mdl->get_function(i);
|
||||
if (!seen.contains(f))
|
||||
{
|
||||
sz = mc->get_num_functions();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
func_decl * f = mc->get_function(i);
|
||||
if (!seen.contains(f)) {
|
||||
TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;);
|
||||
func_interp * val = bv_mdl->get_func_interp(f)->copy();
|
||||
func_interp * val = mc->get_func_interp(f)->copy();
|
||||
float_mdl->register_decl(f, val);
|
||||
}
|
||||
}
|
||||
|
||||
sz = bv_mdl->get_num_uninterpreted_sorts();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
{
|
||||
sort * s = bv_mdl->get_uninterpreted_sort(i);
|
||||
ptr_vector<expr> u = bv_mdl->get_universe(s);
|
||||
|
||||
sz = mc->get_num_uninterpreted_sorts();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
sort * s = mc->get_uninterpreted_sort(i);
|
||||
ptr_vector<expr> u = mc->get_universe(s);
|
||||
float_mdl->register_usort(s, u.size(), u.c_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) {
|
||||
model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) {
|
||||
return alloc(fpa2bv_model_converter, m, conv);
|
||||
}
|
||||
|
|
|
@ -19,78 +19,27 @@ Notes:
|
|||
#ifndef FPA2BV_MODEL_CONVERTER_H_
|
||||
#define FPA2BV_MODEL_CONVERTER_H_
|
||||
|
||||
#include"th_rewriter.h"
|
||||
#include"fpa2bv_converter.h"
|
||||
#include"model_converter.h"
|
||||
#include"bv2fpa_converter.h"
|
||||
|
||||
class fpa2bv_model_converter : public model_converter {
|
||||
ast_manager & m;
|
||||
fpa_util m_fpa_util;
|
||||
bv_util m_bv_util;
|
||||
th_rewriter m_th_rw;
|
||||
bv2fpa_converter * m_bv2fp;
|
||||
|
||||
obj_map<func_decl, expr*> m_const2bv;
|
||||
obj_map<func_decl, expr*> m_rm_const2bv;
|
||||
obj_map<func_decl, func_decl*> m_uf2bvuf;
|
||||
obj_map<func_decl, std::pair<app*, app*> > m_specials;
|
||||
|
||||
public:
|
||||
fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) :
|
||||
fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv):
|
||||
m(m),
|
||||
m_fpa_util(m),
|
||||
m_bv_util(m),
|
||||
m_th_rw(m) {
|
||||
for (obj_map<func_decl, expr*>::iterator it = conv.m_const2bv.begin();
|
||||
it != conv.m_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
m_const2bv.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
for (obj_map<func_decl, expr*>::iterator it = conv.m_rm_const2bv.begin();
|
||||
it != conv.m_rm_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
m_rm_const2bv.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
for (obj_map<func_decl, func_decl*>::iterator it = conv.m_uf2bvuf.begin();
|
||||
it != conv.m_uf2bvuf.end();
|
||||
it++)
|
||||
{
|
||||
m_uf2bvuf.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_specials.begin();
|
||||
it != conv.m_min_max_specials.end();
|
||||
it++) {
|
||||
m_specials.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value.first);
|
||||
m.inc_ref(it->m_value.second);
|
||||
}
|
||||
m_bv2fp(alloc(bv2fpa_converter, m, conv)) {
|
||||
}
|
||||
|
||||
virtual ~fpa2bv_model_converter() {
|
||||
dec_ref_map_key_values(m, m_const2bv);
|
||||
dec_ref_map_key_values(m, m_rm_const2bv);
|
||||
dec_ref_map_key_values(m, m_uf2bvuf);
|
||||
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
|
||||
it != m_specials.end();
|
||||
it++) {
|
||||
m.dec_ref(it->m_key);
|
||||
m.dec_ref(it->m_value.first);
|
||||
m.dec_ref(it->m_value.second);
|
||||
}
|
||||
dealloc(m_bv2fp);
|
||||
}
|
||||
|
||||
virtual void operator()(model_ref & md, unsigned goal_idx) {
|
||||
SASSERT(goal_idx == 0);
|
||||
model * new_model = alloc(model, m);
|
||||
obj_hashtable<func_decl> bits;
|
||||
convert(md.get(), new_model);
|
||||
md = new_model;
|
||||
}
|
||||
|
@ -106,32 +55,12 @@ public:
|
|||
protected:
|
||||
fpa2bv_model_converter(ast_manager & m) :
|
||||
m(m),
|
||||
m_fpa_util(m),
|
||||
m_bv_util(m),
|
||||
m_th_rw(m) {}
|
||||
|
||||
void convert(model * bv_mdl, model * float_mdl);
|
||||
expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig);
|
||||
expr_ref convert_bv2fp(model * bv_mdl, sort * s, expr * bv);
|
||||
expr_ref convert_bv2rm(expr * eval_v);
|
||||
expr_ref convert_bv2rm(model * bv_mdl, expr * val);
|
||||
|
||||
func_interp * convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl);
|
||||
expr_ref rebuild_floats(model * bv_mdl, sort * s, expr * e);
|
||||
|
||||
class array_model {
|
||||
public:
|
||||
func_decl * new_float_fd;
|
||||
func_interp * new_float_fi;
|
||||
func_decl * bv_fd;
|
||||
expr_ref result;
|
||||
array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {}
|
||||
};
|
||||
|
||||
array_model convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl);
|
||||
m_bv2fp(0) {}
|
||||
|
||||
void convert(model_core * mc, model * float_mdl);
|
||||
};
|
||||
|
||||
|
||||
model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv);
|
||||
model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv);
|
||||
|
||||
#endif
|
||||
|
|
161
src/tactic/portfolio/fd_solver.cpp
Normal file
161
src/tactic/portfolio/fd_solver.cpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*++
|
||||
Copyright (c) 2016 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fd_solver.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Finite domain solver.
|
||||
|
||||
Enumeration data-types are translated into bit-vectors, and then
|
||||
the incremental sat-solver is applied to the resulting assertions.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2016-10-17
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
#include "fd_solver.h"
|
||||
#include "solver_na2as.h"
|
||||
#include "tactic.h"
|
||||
#include "inc_sat_solver.h"
|
||||
#include "bv_decl_plugin.h"
|
||||
#include "datatype_decl_plugin.h"
|
||||
#include "fd_rewriter.h"
|
||||
#include "extension_model_converter.h"
|
||||
#include "filter_model_converter.h"
|
||||
#include "ast_pp.h"
|
||||
#include "model_smt2_pp.h"
|
||||
|
||||
class fd_solver : public solver_na2as {
|
||||
ast_manager& m;
|
||||
params_ref m_params;
|
||||
ref<solver> m_solver;
|
||||
fd_rewriter m_rewriter;
|
||||
|
||||
public:
|
||||
|
||||
fd_solver(ast_manager& m, params_ref const& p):
|
||||
solver_na2as(m),
|
||||
m(m),
|
||||
m_params(p),
|
||||
m_solver(mk_inc_sat_solver(m, p)),
|
||||
m_rewriter(m, p)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~fd_solver() {}
|
||||
|
||||
virtual solver* translate(ast_manager& m, params_ref const& p) {
|
||||
return alloc(fd_solver, m, p);
|
||||
}
|
||||
|
||||
virtual void assert_expr(expr * t) {
|
||||
expr_ref tmp(t, m);
|
||||
expr_ref_vector bounds(m);
|
||||
proof_ref tmp_proof(m);
|
||||
m_rewriter(t, tmp, tmp_proof);
|
||||
m_solver->assert_expr(tmp);
|
||||
m_rewriter.flush_side_constraints(bounds);
|
||||
m_solver->assert_expr(bounds);
|
||||
}
|
||||
|
||||
virtual void push_core() {
|
||||
m_rewriter.push();
|
||||
m_solver->push();
|
||||
}
|
||||
|
||||
virtual void pop_core(unsigned n) {
|
||||
m_solver->pop(n);
|
||||
m_rewriter.pop(n);
|
||||
}
|
||||
|
||||
virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
|
||||
return m_solver->check_sat(num_assumptions, assumptions);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); }
|
||||
virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); }
|
||||
virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); }
|
||||
virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); }
|
||||
virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); }
|
||||
virtual void get_unsat_core(ptr_vector<expr> & r) { m_solver->get_unsat_core(r); }
|
||||
virtual void get_model(model_ref & mdl) {
|
||||
m_solver->get_model(mdl);
|
||||
if (mdl) {
|
||||
extend_model(mdl);
|
||||
filter_model(mdl);
|
||||
}
|
||||
}
|
||||
virtual proof * get_proof() { return m_solver->get_proof(); }
|
||||
virtual std::string reason_unknown() const { return m_solver->reason_unknown(); }
|
||||
virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); }
|
||||
virtual void get_labels(svector<symbol> & r) { m_solver->get_labels(r); }
|
||||
virtual ast_manager& get_manager() const { return m; }
|
||||
virtual lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) { return m_solver->find_mutexes(vars, mutexes); }
|
||||
|
||||
virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) {
|
||||
|
||||
datatype_util dt(m);
|
||||
bv_util bv(m);
|
||||
|
||||
// translate enumeration constants to bit-vectors.
|
||||
expr_ref_vector bvars(m), conseq(m);
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
func_decl* f;
|
||||
if (is_app(vars[i]) && is_uninterp_const(vars[i]) && m_rewriter.enum2bv().find(to_app(vars[i])->get_decl(), f)) {
|
||||
bvars.push_back(m.mk_const(f));
|
||||
}
|
||||
else {
|
||||
bvars.push_back(vars[i]);
|
||||
}
|
||||
}
|
||||
lbool r = m_solver->get_consequences(asms, bvars, consequences);
|
||||
|
||||
// translate bit-vector consequences back to enumeration types
|
||||
for (unsigned i = 0; i < consequences.size(); ++i) {
|
||||
expr* a, *b, *u, *v;
|
||||
func_decl* f;
|
||||
rational num;
|
||||
unsigned bvsize;
|
||||
VERIFY(m.is_implies(consequences[i].get(), a, b));
|
||||
if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_rewriter.bv2enum().find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) {
|
||||
SASSERT(num.is_unsigned());
|
||||
expr_ref head(m);
|
||||
ptr_vector<func_decl> const& enums = *dt.get_datatype_constructors(f->get_range());
|
||||
head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()]));
|
||||
consequences[i] = m.mk_implies(a, head);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void filter_model(model_ref& mdl) {
|
||||
filter_model_converter filter(m);
|
||||
obj_map<func_decl, func_decl*>::iterator it = m_rewriter.enum2bv().begin(), end = m_rewriter.enum2bv().end();
|
||||
for (; it != end; ++it) {
|
||||
filter.insert(it->m_value);
|
||||
}
|
||||
filter(mdl, 0);
|
||||
}
|
||||
|
||||
void extend_model(model_ref& mdl) {
|
||||
extension_model_converter ext(m);
|
||||
obj_map<func_decl, expr*>::iterator it = m_rewriter.enum2def().begin(), end = m_rewriter.enum2def().end();
|
||||
for (; it != end; ++it) {
|
||||
ext.insert(it->m_key, it->m_value);
|
||||
|
||||
}
|
||||
ext(mdl, 0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
solver * mk_fd_solver(ast_manager & m, params_ref const & p) {
|
||||
return alloc(fd_solver, m, p);
|
||||
}
|
29
src/tactic/portfolio/fd_solver.h
Normal file
29
src/tactic/portfolio/fd_solver.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*++
|
||||
Copyright (c) 2016 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fd_solver.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Finite domain solver.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2016-10-17
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef FD_SOLVER_H_
|
||||
#define FD_SOLVER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"params.h"
|
||||
|
||||
class solver;
|
||||
|
||||
solver * mk_fd_solver(ast_manager & m, params_ref const & p);
|
||||
|
||||
#endif
|
|
@ -38,6 +38,7 @@ Notes:
|
|||
#include"horn_tactic.h"
|
||||
#include"smt_solver.h"
|
||||
#include"inc_sat_solver.h"
|
||||
#include"fd_solver.h"
|
||||
#include"bv_rewriter.h"
|
||||
|
||||
|
||||
|
@ -98,6 +99,8 @@ static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol
|
|||
bv_rewriter rw(m);
|
||||
if (logic == "QF_BV" && rw.hi_div0())
|
||||
return mk_inc_sat_solver(m, p);
|
||||
if (logic == "QF_FD")
|
||||
return mk_fd_solver(m, p);
|
||||
return mk_smt_solver(m, p, logic);
|
||||
}
|
||||
|
||||
|
@ -116,7 +119,6 @@ public:
|
|||
tactic * t = mk_tactic_for_logic(m, p, l);
|
||||
return mk_combined_solver(mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, l),
|
||||
mk_solver_for_logic(m, p, l),
|
||||
//mk_smt_solver(m, p, l),
|
||||
p);
|
||||
}
|
||||
};
|
||||
|
|
194
src/test/get_consequences.cpp
Normal file
194
src/test/get_consequences.cpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*++
|
||||
Copyright (c) 2016 Microsoft Corporation
|
||||
|
||||
--*/
|
||||
|
||||
#include "inc_sat_solver.h"
|
||||
#include "bv_decl_plugin.h"
|
||||
#include "datatype_decl_plugin.h"
|
||||
#include "reg_decl_plugins.h"
|
||||
#include "ast_pp.h"
|
||||
#include "dt2bv_tactic.h"
|
||||
#include "tactic.h"
|
||||
#include "model_smt2_pp.h"
|
||||
#include "fd_solver.h"
|
||||
|
||||
static expr_ref mk_const(ast_manager& m, char const* name, sort* s) {
|
||||
return expr_ref(m.mk_const(symbol(name), s), m);
|
||||
}
|
||||
|
||||
static expr_ref mk_bool(ast_manager& m, char const* name) {
|
||||
return expr_ref(m.mk_const(symbol(name), m.mk_bool_sort()), m);
|
||||
}
|
||||
|
||||
static expr_ref mk_bv(ast_manager& m, char const* name, unsigned sz) {
|
||||
bv_util bv(m);
|
||||
return expr_ref(m.mk_const(symbol(name), bv.mk_sort(sz)), m);
|
||||
}
|
||||
|
||||
static void test1() {
|
||||
ast_manager m;
|
||||
reg_decl_plugins(m);
|
||||
bv_util bv(m);
|
||||
params_ref p;
|
||||
|
||||
ref<solver> solver = mk_inc_sat_solver(m, p);
|
||||
expr_ref a = mk_bool(m, "a"), b = mk_bool(m, "b"), c = mk_bool(m, "c");
|
||||
expr_ref ba = mk_bv(m, "ba", 3), bb = mk_bv(m, "bb", 3), bc = mk_bv(m, "bc", 3);
|
||||
|
||||
solver->assert_expr(m.mk_implies(a, b));
|
||||
solver->assert_expr(m.mk_implies(b, c));
|
||||
expr_ref_vector asms(m), vars(m), conseq(m);
|
||||
asms.push_back(a);
|
||||
vars.push_back(b);
|
||||
vars.push_back(c);
|
||||
vars.push_back(bb);
|
||||
vars.push_back(bc);
|
||||
solver->assert_expr(m.mk_eq(ba, bc));
|
||||
solver->assert_expr(m.mk_eq(bv.mk_numeral(2, 3), ba));
|
||||
solver->get_consequences(asms, vars, conseq);
|
||||
|
||||
std::cout << conseq << "\n";
|
||||
}
|
||||
|
||||
static void test2() {
|
||||
ast_manager m;
|
||||
reg_decl_plugins(m);
|
||||
bv_util bv(m);
|
||||
datatype_util dtutil(m);
|
||||
params_ref p;
|
||||
|
||||
datatype_decl_plugin & dt = *(static_cast<datatype_decl_plugin*>(m.get_plugin(m.get_family_id("datatype"))));
|
||||
sort_ref_vector new_sorts(m);
|
||||
constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0);
|
||||
constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0);
|
||||
constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0);
|
||||
constructor_decl* constrs[3] = { R, G, B };
|
||||
datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs);
|
||||
VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts));
|
||||
del_constructor_decls(3, constrs);
|
||||
sort* rgb = new_sorts[0].get();
|
||||
|
||||
expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb);
|
||||
ptr_vector<func_decl> const& enums = *dtutil.get_datatype_constructors(rgb);
|
||||
expr_ref r = expr_ref(m.mk_const(enums[0]), m);
|
||||
expr_ref g = expr_ref(m.mk_const(enums[1]), m);
|
||||
expr_ref b = expr_ref(m.mk_const(enums[2]), m);
|
||||
expr_ref val(m);
|
||||
|
||||
// Eliminate enumeration data-types:
|
||||
goal_ref gl = alloc(goal, m);
|
||||
gl->assert_expr(m.mk_not(m.mk_eq(x, r)));
|
||||
gl->assert_expr(m.mk_not(m.mk_eq(x, b)));
|
||||
gl->display(std::cout);
|
||||
obj_map<func_decl, func_decl*> tr;
|
||||
obj_map<func_decl, func_decl*> rev_tr;
|
||||
ref<tactic> dt2bv = mk_dt2bv_tactic(m, p, &tr);
|
||||
goal_ref_buffer result;
|
||||
model_converter_ref mc;
|
||||
proof_converter_ref pc;
|
||||
expr_dependency_ref core(m);
|
||||
(*dt2bv)(gl, result, mc, pc, core);
|
||||
|
||||
// Collect translations from enumerations to bit-vectors
|
||||
obj_map<func_decl, func_decl*>::iterator it = tr.begin(), end = tr.end();
|
||||
for (; it != end; ++it) {
|
||||
rev_tr.insert(it->m_value, it->m_key);
|
||||
}
|
||||
|
||||
// Create bit-vector implication problem
|
||||
val = m.mk_const(tr.find(to_app(x)->get_decl()));
|
||||
std::cout << val << "\n";
|
||||
ptr_vector<expr> fmls;
|
||||
result[0]->get_formulas(fmls);
|
||||
ref<solver> solver = mk_inc_sat_solver(m, p);
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
solver->assert_expr(fmls[i]);
|
||||
}
|
||||
expr_ref_vector asms(m), vars(m), conseq(m);
|
||||
vars.push_back(val);
|
||||
|
||||
// retrieve consequences
|
||||
solver->get_consequences(asms, vars, conseq);
|
||||
|
||||
// Convert consequences over bit-vectors to enumeration types.
|
||||
std::cout << conseq << "\n";
|
||||
for (unsigned i = 0; i < conseq.size(); ++i) {
|
||||
expr* a, *b, *u, *v;
|
||||
func_decl* f;
|
||||
rational num;
|
||||
unsigned bvsize;
|
||||
VERIFY(m.is_implies(conseq[i].get(), a, b));
|
||||
if (m.is_eq(b, u, v) && rev_tr.find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) {
|
||||
SASSERT(num.is_unsigned());
|
||||
expr_ref head(m);
|
||||
head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()]));
|
||||
conseq[i] = m.mk_implies(a, head);
|
||||
}
|
||||
}
|
||||
std::cout << conseq << "\n";
|
||||
}
|
||||
|
||||
void test3() {
|
||||
ast_manager m;
|
||||
reg_decl_plugins(m);
|
||||
bv_util bv(m);
|
||||
datatype_util dtutil(m);
|
||||
params_ref p;
|
||||
|
||||
datatype_decl_plugin & dt = *(static_cast<datatype_decl_plugin*>(m.get_plugin(m.get_family_id("datatype"))));
|
||||
sort_ref_vector new_sorts(m);
|
||||
constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0);
|
||||
constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0);
|
||||
constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0);
|
||||
constructor_decl* constrs[3] = { R, G, B };
|
||||
datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs);
|
||||
VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts));
|
||||
del_constructor_decls(3, constrs);
|
||||
sort* rgb = new_sorts[0].get();
|
||||
|
||||
expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb);
|
||||
ptr_vector<func_decl> const& enums = *dtutil.get_datatype_constructors(rgb);
|
||||
expr_ref r = expr_ref(m.mk_const(enums[0]), m);
|
||||
expr_ref g = expr_ref(m.mk_const(enums[1]), m);
|
||||
expr_ref b = expr_ref(m.mk_const(enums[2]), m);
|
||||
|
||||
ref<solver> fd_solver = mk_fd_solver(m, p);
|
||||
fd_solver->assert_expr(m.mk_not(m.mk_eq(x, r)));
|
||||
fd_solver->assert_expr(m.mk_not(m.mk_eq(x, b)));
|
||||
|
||||
expr_ref_vector asms(m), vars(m), conseq(m);
|
||||
vars.push_back(x);
|
||||
vars.push_back(y);
|
||||
|
||||
VERIFY(l_true == fd_solver->get_consequences(asms, vars, conseq));
|
||||
std::cout << conseq << "\n";
|
||||
conseq.reset();
|
||||
|
||||
fd_solver->push();
|
||||
fd_solver->assert_expr(m.mk_not(m.mk_eq(x, g)));
|
||||
VERIFY(l_false == fd_solver->check_sat(0,0));
|
||||
fd_solver->pop(1);
|
||||
|
||||
VERIFY(l_true == fd_solver->get_consequences(asms, vars, conseq));
|
||||
|
||||
std::cout << conseq << "\n";
|
||||
conseq.reset();
|
||||
|
||||
model_ref mr;
|
||||
fd_solver->get_model(mr);
|
||||
model_smt2_pp(std::cout << "model:\n", m, *mr.get(), 0);
|
||||
|
||||
VERIFY(l_true == fd_solver->check_sat(0,0));
|
||||
fd_solver->get_model(mr);
|
||||
SASSERT(mr.get());
|
||||
model_smt2_pp(std::cout, m, *mr.get(), 0);
|
||||
|
||||
}
|
||||
|
||||
void tst_get_consequences() {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
|
||||
}
|
|
@ -228,6 +228,7 @@ int main(int argc, char ** argv) {
|
|||
TST(pdr);
|
||||
TST_ARGV(ddnf);
|
||||
TST(model_evaluator);
|
||||
TST(get_consequences);
|
||||
//TST_ARGV(hs);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue