3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-10 19:27:06 +00:00
This commit is contained in:
Nikolaj Bjorner 2016-10-19 08:57:16 -07:00
commit ef9486913b
47 changed files with 2232 additions and 1198 deletions

View file

@ -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()

View file

@ -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()

View file

@ -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})

View file

@ -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")

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,6 +1,7 @@
z3_add_component(portfolio
SOURCES
default_tactic.cpp
fd_solver.cpp
smt_strategic_solver.cpp
COMPONENT_DEPENDENCIES
aig_tactic

View file

@ -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

View file

@ -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')

View file

@ -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);

View file

@ -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.

View 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;
});
}

View 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

View file

@ -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) {

View file

@ -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

View file

@ -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;);

View file

@ -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) {

View file

@ -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);
};

View file

@ -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

View file

@ -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:

View 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); }

View 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

View file

@ -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;
}

View file

@ -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"),
))

View file

@ -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););

View file

@ -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());
}
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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) ||

View file

@ -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;

View file

@ -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);
}

View file

@ -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)")

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View 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);
}

View 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

View file

@ -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);
}
};

View 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();
}

View file

@ -228,6 +228,7 @@ int main(int argc, char ** argv) {
TST(pdr);
TST_ARGV(ddnf);
TST(model_evaluator);
TST(get_consequences);
//TST_ARGV(hs);
}