3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-04 05:11:21 +00:00

add cube mode

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-09-24 10:53:57 -07:00
commit ae9a6664d4
144 changed files with 6012 additions and 3174 deletions

View file

@ -60,17 +60,15 @@ env:
- LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug
# macOS (a.k.a OSX) support
# FIXME: macOS support is temporarily disabled due to @wintersteiger 's concerns.
# See https://github.com/Z3Prover/z3/pull/1207#issuecomment-322200998
# matrix:
# include:
# # For now just test a single configuration. macOS builds on TravisCI are
# # very slow so we should keep the number of configurations we test on this
# # OS to a minimum.
# - os: osx
# osx_image: xcode8.3
# # Note: Apple Clang does not support OpenMP
# env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0
matrix:
include:
# For now just test a single configuration. macOS builds on TravisCI are
# very slow so we should keep the number of configurations we test on this
# OS to a minimum.
- os: osx
osx_image: xcode8.3
# Note: Apple Clang does not support OpenMP
env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0
script:
# Use `travis_wait` when doing LTO builds because this configuration will
# have long link times during which it will not show any output which

View file

@ -51,8 +51,6 @@ public:
virtual void operator()(model_ref & md) { operator()(md, 0); }
//void display(std::ostream & out);
virtual model_converter * translate(ast_translation & translator) {
ackr_info_ref retv_info = info->translate(translator);
if (fixed_model) {
@ -63,6 +61,7 @@ public:
return alloc(ackr_model_converter, translator.to(), retv_info);
}
}
protected:
ast_manager & m;
const ackr_info_ref info;
@ -85,13 +84,15 @@ void ackr_model_converter::convert_constants(model * source, model * destination
TRACE("ackr_model", tout << "converting constants\n";);
obj_map<func_decl, func_interp*> interpretations;
model_evaluator evaluator(*source);
evaluator.set_model_completion(true);
for (unsigned i = 0; i < source->get_num_constants(); i++) {
func_decl * const c = source->get_constant(i);
app * const term = info->find_term(c);
expr * value = source->get_const_interp(c);
if (!term) {
destination->register_decl(c, value);
} else {
}
else {
add_entry(evaluator, term, value, interpretations);
}
}
@ -133,8 +134,14 @@ void ackr_model_converter::add_entry(model_evaluator & evaluator,
args.push_back(arg_value);
}
if (fi->get_entry(args.c_ptr()) == 0) {
TRACE("ackr_model",
tout << mk_ismt2_pp(declaration, m) << " args: " << std::endl;
for (unsigned i = 0; i < args.size(); i++)
tout << mk_ismt2_pp(args.get(i), m) << std::endl;
tout << " -> " << mk_ismt2_pp(value, m) << "\n"; );
fi->insert_new_entry(args.c_ptr(), value);
} else {
}
else {
TRACE("ackr_model", tout << "entry already present\n";);
}
}

View file

@ -1204,16 +1204,8 @@ extern "C" {
case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV;
case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL;
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
case OP_FPA_INTERNAL_MIN_I: return Z3_OP_FPA_MIN_I;
case OP_FPA_INTERNAL_MAX_I: return Z3_OP_FPA_MAX_I;
case OP_FPA_INTERNAL_BV2RM:
case OP_FPA_INTERNAL_BVWRAP:
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
case OP_FPA_INTERNAL_MAX_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP;
case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM;
return Z3_OP_UNINTERPRETED;
default:
return Z3_OP_INTERNAL;

View file

@ -354,7 +354,7 @@ namespace z3 {
Z3_error_code check_error() const { return m_ctx->check_error(); }
friend void check_context(object const & a, object const & b);
};
inline void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); }
inline void check_context(object const & a, object const & b) { (void)a; (void)b; assert(a.m_ctx == b.m_ctx); }
class symbol : public object {
Z3_symbol m_sym;

View file

@ -285,8 +285,7 @@ public class Optimize extends Z3Object {
**/
public String getReasonUnknown()
{
return Native.optimizeGetReasonUnknown(getContext().nCtx(),
getNativeObject());
return Native.optimizeGetReasonUnknown(getContext().nCtx(), getNativeObject());
}
/**

View file

@ -36,11 +36,7 @@ public class Sort extends AST
Sort other = (Sort) o;
return (getContext().nCtx() == other.getContext().nCtx()) &&
(Native.isEqSort(
getContext().nCtx(),
getNativeObject(),
other.getNativeObject()
));
(Native.isEqSort(getContext().nCtx(), getNativeObject(), other.getNativeObject()));
}
/**

View file

@ -979,7 +979,23 @@ typedef enum
- Z3_OP_FPA_TO_IEEE_BV: Floating-point conversion to IEEE-754 bit-vector
- Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional information is exposed. Tools may use the string representation of the function declaration to obtain more information.
- Z3_OP_FPA_BVWRAP: (Implicitly) represents the internal bitvector-
representation of a floating-point term (used for the lazy encoding
of non-relevant terms in theory_fpa)
- Z3_OP_FPA_BV2RM: Conversion of a 3-bit bit-vector term to a
floating-point rouding-mode term
The conversion uses the following values:
0 = 000 = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN,
1 = 001 = Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY,
2 = 010 = Z3_OP_FPA_RM_TOWARD_POSITIVE,
3 = 011 = Z3_OP_FPA_RM_TOWARD_NEGATIVE,
4 = 100 = Z3_OP_FPA_RM_TOWARD_ZERO.
- Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional
information is exposed. Tools may use the string representation of the
function declaration to obtain more information.
- Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols.
*/
@ -1263,8 +1279,8 @@ typedef enum {
Z3_OP_FPA_TO_IEEE_BV,
Z3_OP_FPA_MIN_I,
Z3_OP_FPA_MAX_I,
Z3_OP_FPA_BVWRAP,
Z3_OP_FPA_BV2RM,
Z3_OP_INTERNAL,

View file

@ -1714,8 +1714,15 @@ ast * ast_manager::register_node_core(ast * n) {
SASSERT(m_ast_table.contains(n));
}
n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk();
static unsigned count = 0;
if (n->m_id == 404) {
++count;
//if (count == 2) SASSERT(false);
}
TRACE("ast", tout << "Object " << n->m_id << " was created.\n";);
TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";);
// increment reference counters

View file

@ -584,6 +584,8 @@ class smt2_printer {
string_buffer<> buf;
buf.append("(:var ");
buf.append(v->get_idx());
//buf.append(" ");
//buf.append(v->get_sort()->get_name().str().c_str());
buf.append(")");
f = mk_string(m(), buf.c_str());
}

View file

@ -738,6 +738,7 @@ void bv_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const
op_names.push_back(builtin_name("ext_rotate_right",OP_EXT_ROTATE_RIGHT));
op_names.push_back(builtin_name("int2bv",OP_INT2BV));
op_names.push_back(builtin_name("bv2int",OP_BV2INT));
op_names.push_back(builtin_name("bv2nat",OP_BV2INT));
op_names.push_back(builtin_name("mkbv",OP_MKBV));
}
}

View file

@ -62,8 +62,8 @@ bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) :
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();
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_ufs.begin();
it != conv.m_min_max_ufs.end();
it++) {
m_specials.insert(it->m_key, it->m_value);
m.inc_ref(it->m_key);
@ -263,7 +263,7 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl *
unsigned arity = bv_f->get_arity();
func_interp * bv_fi = mc->get_func_interp(bv_f);
if (bv_fi != 0) {
if (bv_fi) {
fpa_rewriter rw(m);
expr_ref ai(m);
result = alloc(func_interp, m, arity);
@ -285,16 +285,32 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl *
bv_fres = bv_fe->get_result();
ft_fres = rebuild_floats(mc, rng, to_app(bv_fres));
m_th_rw(ft_fres);
TRACE("bv2fpa",
for (unsigned i = 0; i < new_args.size(); i++)
tout << mk_ismt2_pp(bv_args[i], m) << " == " <<
mk_ismt2_pp(new_args[i], m) << std::endl;
tout << mk_ismt2_pp(bv_fres, m) << " == " << mk_ismt2_pp(ft_fres, m) << std::endl;);
func_entry * fe = result->get_entry(new_args.c_ptr());
if (fe == 0)
result->insert_new_entry(new_args.c_ptr(), ft_fres);
else {
// The BV model may have multiple equivalent entries using different
// representations of NaN. We can only keep one and we check that
// the results for all those entries are the same.
if (ft_fres != fe->get_result())
throw default_exception("BUG: UF function entries disagree with each other");
}
}
app_ref bv_els(m);
expr_ref ft_els(m);
bv_els = (app*)bv_fi->get_else();
if (bv_els != 0) {
ft_els = rebuild_floats(mc, rng, bv_els);
m_th_rw(ft_els);
result->set_else(ft_els);
}
}
return result;
}
@ -382,7 +398,7 @@ void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_mo
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;);
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());
}
@ -446,15 +462,35 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode
target_model->register_decl(f, val);
}
}
else {
if (it->get_key().get_family_id() == m_fpa_util.get_fid()) {
// it->m_value contains the model for the unspecified cases of it->m_key.
func_interp * fmv = convert_func_interp(mc, f, it->m_value);
if (fmv) {
#if 0
// Upon request, add this 'recursive' definition?
unsigned n = fmv->get_arity();
expr_ref_vector args(m);
for (unsigned i = 0; i < n; i++)
args.push_back(m.mk_var(i, f->get_domain()[i]));
fmv->set_else(m.mk_app(it->m_key, n, args.c_ptr()));
#else
fmv->set_else(0);
#endif
target_model->register_decl(f, fmv);
}
}
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++) {
@ -488,7 +524,6 @@ void bv2fpa_converter::display(std::ostream & out) {
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) {
@ -536,23 +571,3 @@ bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) {
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

@ -50,7 +50,6 @@ public:
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);

View file

@ -230,39 +230,7 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result)
result = m_util.mk_fp(sgn, e, s);
}
void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result) {
if (m_util.is_float(rng)) {
unsigned ebits = m_util.get_ebits(rng);
unsigned sbits = m_util.get_sbits(rng);
unsigned bv_sz = ebits + sbits;
app_ref na(m);
na = m.mk_app(fbv, fbv->get_arity(), new_args);
result = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na),
m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na),
m_bv_util.mk_extract(sbits - 2, 0, na));
}
else if (m_util.is_rm(rng)) {
app_ref na(m);
na = m.mk_app(fbv, fbv->get_arity(), new_args);
result = m_util.mk_bv2rm(na);
}
else
result = m.mk_app(fbv, fbv->get_arity(), new_args);
}
func_decl * fpa2bv_converter::get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity) {
func_decl * res;
if (!m_uf2bvuf.find(f, res)) {
res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), arity, f->get_domain(), bv_rng);
m_uf2bvuf.insert(f, res);
m.inc_ref(f);
m.inc_ref(res);
TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;);
}
return res;
}
void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result)
void fpa2bv_converter::mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result)
{
TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; );
@ -278,7 +246,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a
unsigned sbits = m_util.get_sbits(rng);
unsigned bv_sz = ebits+sbits;
bv_rng = m_bv_util.mk_sort(bv_sz);
func_decl * bv_f = get_bv_uf(f, bv_rng, num);
func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng);
bv_app = m.mk_app(bv_f, num, args);
flt_app = m_util.mk_fp(m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv_app),
m_bv_util.mk_extract(sbits+ebits-2, sbits-1, bv_app),
@ -291,7 +259,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a
sort_ref bv_rng(m);
expr_ref new_eq(m);
bv_rng = m_bv_util.mk_sort(3);
func_decl * bv_f = get_bv_uf(f, bv_rng, num);
func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng);
bv_app = m.mk_app(bv_f, num, args);
flt_app = m_util.mk_bv2rm(bv_app);
new_eq = m.mk_eq(fapp, flt_app);
@ -1211,36 +1179,9 @@ void fpa2bv_converter::mk_abs(sort * s, expr_ref & x, expr_ref & result) {
}
void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
expr_ref x(m), y(m);
x = args[0];
y = args[1];
expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m);
x_is_zero = m_util.mk_is_zero(x);
y_is_zero = m_util.mk_is_zero(y);
both_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m);
x_is_positive = m_util.mk_is_positive(x);
x_is_negative = m_util.mk_is_negative(x);
y_is_positive = m_util.mk_is_positive(y);
y_is_negative = m_util.mk_is_negative(y);
pn = m.mk_and(x_is_positive, y_is_negative);
np = m.mk_and(x_is_negative, y_is_positive);
pn_or_np = m.mk_or(pn, np);
expr_ref c(m), v(m);
c = m.mk_and(both_are_zero, pn_or_np);
v = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, x, y);
// Note: This requires BR_REWRITE_FULL afterwards.
expr_ref min_i(m);
min_i = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MIN_I, x, y);
m_simp.mk_ite(c, v, min_i, result);
}
void fpa2bv_converter::mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
expr * x = args[0], * y = args[1];
@ -1249,23 +1190,78 @@ void fpa2bv_converter::mk_min_i(func_decl * f, unsigned num, expr * const * args
split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_sig);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
m_simp.mk_and(x_is_zero, y_is_zero, both_zero);
expr_ref bv0(m), bv1(m);
bv0 = m_bv_util.mk_numeral(0, 1);
bv1 = m_bv_util.mk_numeral(1, 1);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m);
mk_is_nan(x, x_is_nan);
mk_is_nan(y, y_is_nan);
mk_pzero(f, pzero);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
xy_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref sgn_eq(m), sgn_diff(m);
sgn_eq = m.mk_eq(x_sgn, y_sgn);
sgn_diff = m.mk_not(sgn_eq);
expr_ref x_is_pos(m), x_is_neg(m);
expr_ref y_is_pos(m), y_is_neg(m);
expr_ref pn(m), np(m), pn_or_np_zeros(m);
mk_is_pos(x, x_is_pos);
mk_is_pos(y, y_is_pos);
mk_is_neg(x, x_is_neg);
mk_is_neg(y, y_is_neg);
pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn)));
expr_ref lt(m);
mk_float_lt(f, num, args, lt);
expr_ref unspec(m);
unspec = mk_min_max_unspecified(f, x, y);
mk_ite(lt, x, y, result);
mk_ite(both_zero, y, result, result);
expr_ref x_lt_y(m);
mk_float_lt(f, num, args, x_lt_y);
mk_ite(x_lt_y, x, y, result);
mk_ite(xy_are_zero, y, result, result);
mk_ite(pn_or_np_zeros, unspec, result, result);
mk_ite(y_is_nan, x, result, result);
mk_ite(x_is_nan, y, result, result);
SASSERT(is_well_sorted(m, result));
}
void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
expr * x = args[0], *y = args[1];
expr * x_sgn, *x_sig, *x_exp;
expr * y_sgn, *y_sig, *y_exp;
split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_sig);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m);
mk_is_nan(x, x_is_nan);
mk_is_nan(y, y_is_nan);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
xy_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref x_is_pos(m), x_is_neg(m);
expr_ref y_is_pos(m), y_is_neg(m);
expr_ref pn(m), np(m), pn_or_np_zeros(m);
mk_is_pos(x, x_is_pos);
mk_is_pos(y, y_is_pos);
mk_is_neg(x, x_is_neg);
mk_is_neg(y, y_is_neg);
pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn)));
expr_ref unspec(m);
unspec = mk_min_max_unspecified(f, x, y);
expr_ref x_gt_y(m);
mk_float_gt(f, num, args, x_gt_y);
mk_ite(x_gt_y, x, y, result);
mk_ite(xy_are_zero, y, result, result);
mk_ite(pn_or_np_zeros, unspec, result, result);
mk_ite(y_is_nan, x, result, result);
mk_ite(x_is_nan, y, result, result);
@ -1281,10 +1277,10 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr
// There is no "hardware interpretation" for fp.min/fp.max.
std::pair<app*, app*> decls(0, 0);
if (!m_min_max_specials.find(f, decls)) {
if (!m_min_max_ufs.find(f, decls)) {
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
m_min_max_specials.insert(f, decls);
m_min_max_ufs.insert(f, decls);
m.inc_ref(f);
m.inc_ref(decls.first);
m.inc_ref(decls.second);
@ -1303,68 +1299,6 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr
return res;
}
void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
expr_ref x(m), y(m);
x = args[0];
y = args[1];
expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m);
x_is_zero = m_util.mk_is_zero(x);
y_is_zero = m_util.mk_is_zero(y);
both_are_zero = m.mk_and(x_is_zero, y_is_zero);
expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m);
x_is_positive = m_util.mk_is_positive(x);
x_is_negative = m_util.mk_is_negative(x);
y_is_positive = m_util.mk_is_positive(y);
y_is_negative = m_util.mk_is_negative(y);
pn = m.mk_and(x_is_positive, y_is_negative);
np = m.mk_and(x_is_negative, y_is_positive);
pn_or_np = m.mk_or(pn, np);
expr_ref c(m), v(m);
c = m.mk_and(both_are_zero, pn_or_np);
v = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, x, y);
// Note: This requires BR_REWRITE_FULL afterwards.
expr_ref max_i(m);
max_i = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MAX_I, x, y);
m_simp.mk_ite(c, v, max_i, result);
}
void fpa2bv_converter::mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr * x = args[0], *y = args[1];
expr * x_sgn, *x_sig, *x_exp;
expr * y_sgn, *y_sig, *y_exp;
split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_sig);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m);
mk_is_zero(x, x_is_zero);
mk_is_zero(y, y_is_zero);
m_simp.mk_and(x_is_zero, y_is_zero, both_zero);
mk_is_nan(x, x_is_nan);
mk_is_nan(y, y_is_nan);
mk_pzero(f, pzero);
expr_ref sgn_diff(m), sgn_eq(m);
sgn_eq = m.mk_eq(x_sgn, y_sgn);
sgn_diff = m.mk_not(sgn_eq);
expr_ref gt(m);
mk_float_gt(f, num, args, gt);
mk_ite(gt, x, y, result);
mk_ite(both_zero, y, result, result);
mk_ite(y_is_nan, x, result, result);
mk_ite(x_is_nan, y, result, result);
SASSERT(is_well_sorted(m, result));
}
void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 4);
SASSERT(m_util.is_bv2rm(args[0]));
@ -2855,8 +2789,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar
tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;);
expr_ref unspec(m);
unspec = mk_to_real_unspecified(ebits, sbits);
mk_to_real_unspecified(f, num, args, unspec);
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);
@ -3151,48 +3084,33 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const *
unsigned ebits = m_util.get_ebits(fp_srt);
unsigned sbits = m_util.get_sbits(fp_srt);
expr_ref nanv(m);
if (m_hi_fp_unspecified)
// The "hardware interpretation" is 01...10...01.
nanv = 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))));
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 unspec(m);
mk_to_ieee_bv_unspecified(f, num, args, unspec);
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);
join_fp(x, sgn_e_s);
m_simp.mk_ite(x_is_nan, unspec, 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();
SASSERT(num == 1);
SASSERT(m_util.is_float(args[0]));
unsigned ebits = f->get_domain()[0]->get_parameter(0).get_int();
unsigned sbits = f->get_domain()[0]->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));
}
if (m_hi_fp_unspecified)
mk_nan(f->get_range(), result);
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 * n = args[0];
expr_ref n_bv(m);
join_fp(n, n_bv);
sort * domain[1] = { m.get_sort(n_bv) };
func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
result = m.mk_app(f_bv, n_bv);
expr_ref exp_bv(m), exp_all_ones(m);
exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result);
@ -3204,7 +3122,6 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex
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));
@ -3238,18 +3155,13 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
mk_is_nzero(x, x_is_nzero);
// NaN, Inf, or negative (except -0) -> unspecified
expr_ref c1(m), v1(m);
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)));
v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
}
else {
expr_ref c1(m), v1(m), unspec_v(m);
c1 = m.mk_or(x_is_nan, x_is_inf);
v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz);
}
mk_to_bv_unspecified(f, num, args, unspec_v);
v1 = unspec_v;
dbg_decouple("fpa2bv_to_bv_c1", c1);
// +-Zero -> 0
// +-0 -> 0
expr_ref c2(m), v2(m);
c2 = x_is_zero;
v2 = m_bv_util.mk_numeral(rational(0), bv_srt);
@ -3270,60 +3182,57 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
SASSERT(m_bv_util.get_bv_size(exp) == ebits);
SASSERT(m_bv_util.get_bv_size(lz) == ebits);
unsigned sig_sz = m_bv_util.get_bv_size(sig);
SASSERT(sig_sz == sbits);
unsigned sig_sz = sbits;
if (sig_sz < (bv_sz + 3))
sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz-sig_sz+3));
sig_sz = m_bv_util.get_bv_size(sig);
SASSERT(sig_sz >= (bv_sz + 3));
expr_ref exp_m_lz(m), e_m_lz_m_bv_sz(m), shift(m), bv0_e2(m), shift_abs(m), shift_le_0(m);
// x is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long
expr_ref exp_m_lz(m), e_m_lz_m_bv_sz(m), shift(m), is_neg_shift(m), big_sig(m);
exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp),
m_bv_util.mk_zero_extend(2, lz));
e_m_lz_m_bv_sz = m_bv_util.mk_bv_sub(exp_m_lz,
m_bv_util.mk_numeral(bv_sz - 1, ebits + 2));
shift = m_bv_util.mk_bv_neg(e_m_lz_m_bv_sz);
bv0_e2 = m_bv_util.mk_numeral(0, ebits + 2);
shift_le_0 = m_bv_util.mk_sle(shift, bv0_e2);
shift_abs = m.mk_ite(shift_le_0, e_m_lz_m_bv_sz, shift);
SASSERT(m_bv_util.get_bv_size(shift) == ebits + 2);
SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits + 2);
dbg_decouple("fpa2bv_to_bv_shift", shift);
dbg_decouple("fpa2bv_to_bv_shift_abs", shift_abs);
// x is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long
// [1][ ... sig ... ][r][g][ ... s ...]
// [ ... ubv ... ][r][g][ ... s ... ]
// big_sig is +- [... bv_sz+2 bits ...].[r][g][ ... sbits-1 ... ]
big_sig = m_bv_util.mk_zero_extend(bv_sz+2, sig);
unsigned big_sig_sz = sig_sz+bv_sz+2;
SASSERT(m_bv_util.get_bv_size(big_sig) == big_sig_sz);
shift_abs = m_bv_util.mk_zero_extend(sig_sz - ebits - 2, shift_abs);
SASSERT(m_bv_util.get_bv_size(shift_abs) == sig_sz);
expr_ref c_in_limits(m);
if (!is_signed)
c_in_limits = m_bv_util.mk_sle(bv0_e2, shift);
else {
expr_ref one_sle_shift(m), one_eq_shift(m), p2(m), sig_is_p2(m), shift1_and_sig_p2(m);
one_sle_shift = m_bv_util.mk_sle(m_bv_util.mk_numeral(1, ebits + 2), shift);
one_eq_shift = m.mk_eq(m_bv_util.mk_numeral(0, ebits + 2), shift);
p2 = m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, sig_sz-1));
sig_is_p2 = m.mk_eq(sig, p2);
shift1_and_sig_p2 = m.mk_and(one_eq_shift, sig_is_p2);
c_in_limits = m.mk_or(one_sle_shift, shift1_and_sig_p2);
is_neg_shift = m_bv_util.mk_sle(exp_m_lz, m_bv_util.mk_numeral(0, ebits+2));
shift = m.mk_ite(is_neg_shift, m_bv_util.mk_bv_neg(exp_m_lz), exp_m_lz);
if (ebits+2 < big_sig_sz)
shift = m_bv_util.mk_zero_extend(big_sig_sz-ebits-2, shift);
else if (ebits+2 > big_sig_sz) {
expr_ref upper(m);
upper = m_bv_util.mk_extract(big_sig_sz, ebits+2, shift);
shift = m_bv_util.mk_extract(ebits+1, 0, shift);
shift = m.mk_ite(m.mk_eq(upper, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(upper))),
shift,
m_bv_util.mk_numeral(big_sig_sz-1, ebits+2));
}
dbg_decouple("fpa2bv_to_bv_in_limits", c_in_limits);
dbg_decouple("fpa2bv_to_bv_shift_uncapped", shift);
SASSERT(m_bv_util.get_bv_size(shift) == m_bv_util.get_bv_size(big_sig));
dbg_decouple("fpa2bv_to_bv_big_sig", big_sig);
expr_ref r_shifted_sig(m), l_shifted_sig(m);
r_shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs);
l_shifted_sig = m_bv_util.mk_bv_shl(sig, m_bv_util.mk_bv_sub(
m_bv_util.mk_numeral(m_bv_util.get_bv_size(sig), m_bv_util.get_bv_size(sig)),
shift_abs));
dbg_decouple("fpa2bv_to_bv_r_shifted_sig", r_shifted_sig);
dbg_decouple("fpa2bv_to_bv_l_shifted_sig", l_shifted_sig);
expr_ref shift_limit(m);
shift_limit = m_bv_util.mk_numeral(bv_sz+2, m_bv_util.get_bv_size(shift));
shift = m.mk_ite(m_bv_util.mk_ule(shift, shift_limit), shift, shift_limit);
dbg_decouple("fpa2bv_to_bv_shift_limit", shift_limit);
dbg_decouple("fpa2bv_to_bv_is_neg_shift", is_neg_shift);
dbg_decouple("fpa2bv_to_bv_shift", shift);
expr_ref last(m), round(m), sticky(m);
last = m_bv_util.mk_extract(sig_sz - bv_sz - 0, sig_sz - bv_sz - 0, r_shifted_sig);
round = m_bv_util.mk_extract(sig_sz - bv_sz - 1, sig_sz - bv_sz - 1, r_shifted_sig);
sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, l_shifted_sig.get());
expr_ref big_sig_shifted(m), int_part(m), last(m), round(m), stickies(m), sticky(m);
big_sig_shifted = m.mk_ite(is_neg_shift, m_bv_util.mk_bv_lshr(big_sig, shift),
m_bv_util.mk_bv_shl(big_sig, shift));
int_part = m_bv_util.mk_extract(big_sig_sz-1, big_sig_sz-(bv_sz+3), big_sig_shifted);
SASSERT(m_bv_util.get_bv_size(int_part) == bv_sz+3);
last = m_bv_util.mk_extract(big_sig_sz-(bv_sz+3), big_sig_sz-(bv_sz+3), big_sig_shifted);
round = m_bv_util.mk_extract(big_sig_sz-(bv_sz+4), big_sig_sz-(bv_sz+4), big_sig_shifted);
stickies = m_bv_util.mk_extract(big_sig_sz-(bv_sz+5), 0, big_sig_shifted);
sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, stickies.get());
dbg_decouple("fpa2bv_to_bv_big_sig_shifted", big_sig_shifted);
dbg_decouple("fpa2bv_to_bv_int_part", int_part);
dbg_decouple("fpa2bv_to_bv_last", last);
dbg_decouple("fpa2bv_to_bv_round", round);
dbg_decouple("fpa2bv_to_bv_sticky", sticky);
@ -3333,33 +3242,31 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
SASSERT(m_bv_util.get_bv_size(rounding_decision) == 1);
dbg_decouple("fpa2bv_to_bv_rounding_decision", rounding_decision);
expr_ref unrounded_sig(m), pre_rounded(m), inc(m);
unrounded_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_extract(sig_sz - 1, sig_sz - bv_sz, r_shifted_sig));
inc = m_bv_util.mk_zero_extend(1, m_bv_util.mk_zero_extend(bv_sz - 1, rounding_decision));
pre_rounded = m_bv_util.mk_bv_add(unrounded_sig, inc);
expr_ref inc(m), pre_rounded(m);
inc = m_bv_util.mk_zero_extend(bv_sz+2, rounding_decision);
pre_rounded = m_bv_util.mk_bv_add(int_part, inc);
dbg_decouple("fpa2bv_to_bv_inc", inc);
dbg_decouple("fpa2bv_to_bv_pre_rounded", pre_rounded);
expr_ref rnd_overflow(m), rnd(m), rnd_has_overflown(m);
rnd_overflow = m_bv_util.mk_extract(bv_sz, bv_sz, pre_rounded);
rnd = m_bv_util.mk_extract(bv_sz - 1, 0, pre_rounded);
rnd_has_overflown = m.mk_eq(rnd_overflow, bv1);
dbg_decouple("fpa2bv_to_bv_rnd_has_overflown", rnd_has_overflown);
pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded);
if (is_signed) {
expr_ref sgn_eq_1(m), neg_rnd(m);
sgn_eq_1 = m.mk_eq(sgn, bv1);
neg_rnd = m_bv_util.mk_bv_neg(rnd);
m_simp.mk_ite(sgn_eq_1, neg_rnd, rnd, rnd);
expr_ref ll(m), ul(m), in_range(m);
if (!is_signed) {
ll = m_bv_util.mk_numeral(0, bv_sz+3);
ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz));
}
else {
ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1)));
ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_numeral(-1, bv_sz-1));
}
in_range = m.mk_and(m_bv_util.mk_sle(ll, pre_rounded), m_bv_util.mk_sle(pre_rounded, ul));
dbg_decouple("fpa2bv_to_bv_in_range", in_range);
dbg_decouple("fpa2bv_to_bv_rnd", rnd);
expr_ref rounded(m);
rounded = m_bv_util.mk_extract(bv_sz-1, 0, pre_rounded);
dbg_decouple("fpa2bv_to_bv_rounded", rounded);
expr_ref unspec(m);
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(m.mk_not(in_range), unspec_v, rounded);
result = m.mk_ite(c2, v2, result);
result = m.mk_ite(c1, v1, result);
@ -3378,85 +3285,42 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg
mk_to_bv(f, num, args, true, result);
}
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());
void fpa2bv_converter::mk_to_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
SASSERT(m_util.is_bv2rm(args[0]));
SASSERT(m_util.is_float(args[1]));
if (m_hi_fp_unspecified)
result = m_bv_util.mk_numeral(0, width);
result = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(f->get_range()));
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);
expr * rm_bv = to_app(args[0])->get_arg(0);
expr * n = args[1];
expr_ref n_bv(m);
join_fp(n, n_bv);
sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(n_bv) };
func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
result = m.mk_app(f_bv, rm_bv, n_bv);
}
TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
TRACE("fpa2bv_to_bv_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 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;
}
void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 1);
if (m_hi_fp_unspecified)
result = m_arith_util.mk_numeral(rational(0), false);
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);
}
}
expr * n = args[0];
expr_ref n_bv(m);
join_fp(n, n_bv);
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;
sort * domain[1] = { m.get_sort(n_bv) };
func_decl * f_bv = mk_bv_uf(f, domain, f->get_range());
result = m.mk_app(f_bv, n_bv);
}
}
void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@ -3467,6 +3331,7 @@ void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, e
result = m_util.mk_fp(args[0], args[1], args[2]);
TRACE("fpa2bv_mk_fp", tout << "mk_fp result = " << mk_ismt2_pp(result, m) << std::endl;);
}
void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const {
SASSERT(m_util.is_fp(e));
SASSERT(to_app(e)->get_num_args() == 3);
@ -3485,6 +3350,14 @@ void fpa2bv_converter::split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_r
sig = e_sig;
}
void fpa2bv_converter::join_fp(expr * e, expr_ref & res) {
SASSERT(m_util.is_fp(e));
SASSERT(to_app(e)->get_num_args() == 3);
expr *sgn, *exp, *sig;
split_fp(e, sgn, exp, sig);
res = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, exp), sig);
}
void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
split_fp(e, sgn, exp, sig);
@ -4051,7 +3924,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
// put the sticky bit into the significand.
expr_ref ext_sticky(m);
ext_sticky = m_bv_util.mk_zero_extend(sbits+1, sticky);
expr * tmp[] = { sig, ext_sticky };
expr * tmp[2] = { sig, ext_sticky };
sig = m_bv_util.mk_bv_or(2, tmp);
SASSERT(is_well_sorted(m, sig));
SASSERT(m_bv_util.get_bv_size(sig) == sbits+2);
@ -4221,13 +4094,25 @@ void fpa2bv_converter::reset(void) {
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_min_max_specials.begin();
it != m_min_max_specials.end();
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_min_max_ufs.begin();
it != m_min_max_ufs.end();
it++) {
m.dec_ref(it->m_key);
m.dec_ref(it->m_value.first);
m.dec_ref(it->m_value.second);
}
m_min_max_specials.reset();
m_min_max_ufs.reset();
m_extra_assertions.reset();
}
func_decl * fpa2bv_converter::mk_bv_uf(func_decl * f, sort * const * domain, sort * range) {
func_decl * res;
if (!m_uf2bvuf.find(f, res)) {
res = m.mk_fresh_func_decl(0, f->get_arity(), domain, range);
m_uf2bvuf.insert(f, res);
m.inc_ref(f);
m.inc_ref(res);
TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;);
}
return res;
}

View file

@ -53,7 +53,7 @@ protected:
const2bv_t m_const2bv;
const2bv_t m_rm_const2bv;
uf2bvuf_t m_uf2bvuf;
special_t m_min_max_specials;
special_t m_min_max_ufs;
friend class fpa2bv_model_converter;
friend class bv2fpa_converter;
@ -76,6 +76,7 @@ public:
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;
void join_fp(expr * e, expr_ref & res);
void mk_eq(expr * a, expr * b, expr_ref & result);
void mk_ite(expr * c, expr * t, expr * f, expr_ref & result);
@ -86,7 +87,7 @@ public:
void mk_numeral(sort * s, mpf const & v, expr_ref & result);
virtual void mk_const(func_decl * f, expr_ref & result);
virtual void mk_rm_const(func_decl * f, expr_ref & result);
virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
virtual void mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_var(unsigned base_inx, sort * srt, expr_ref & result);
void mk_pinf(func_decl * f, expr_ref & result);
@ -138,27 +139,23 @@ public:
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_bv_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; }
void mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y);
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_min_max_unspecified(func_decl * f, expr * x, expr * y);
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; };
special_t const & get_min_max_specials() const { return m_min_max_ufs; };
const2bv_t const & get_const2bv() const { return m_const2bv; };
const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; };
uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; };
@ -202,12 +199,6 @@ protected:
void mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result);
sort_ref replace_float_sorts(sort * s);
func_decl_ref replace_function(func_decl * f);
expr_ref replace_float_arg(expr * a);
void mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result);
func_decl * get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity);
private:
void mk_nan(sort * s, expr_ref & result);
void mk_nzero(sort * s, expr_ref & result);
@ -227,9 +218,7 @@ private:
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);
func_decl * mk_bv_uf(func_decl * f, sort * const * domain, sort * range);
};
#endif

View file

@ -124,6 +124,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_DONE;
case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_DONE;
case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
@ -143,24 +145,12 @@ 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;
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_min_max_unspecified(f, args[0], args[1]); return BR_DONE;
case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_BVWRAP:
case OP_FPA_INTERNAL_BV2RM:
case OP_FPA_BVWRAP:
case OP_FPA_BV2RM:
return BR_FAILED;
default:
@ -173,7 +163,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
{
SASSERT(!m_conv.is_float_family(f));
if (m_conv.fu().contains_floats(f)) {
m_conv.mk_function(f, num, args, result);
m_conv.mk_uf(f, num, args, result);
return BR_DONE;
}
}

View file

@ -361,10 +361,6 @@ func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters
case OP_FPA_REM: name = "fp.rem"; break;
case OP_FPA_MIN: name = "fp.min"; break;
case OP_FPA_MAX: name = "fp.max"; break;
case OP_FPA_INTERNAL_MIN_I: name = "fp.min_i"; break;
case OP_FPA_INTERNAL_MAX_I: name = "fp.max_i"; break;
case OP_FPA_INTERNAL_MIN_UNSPECIFIED: name = "fp.min_unspecified"; break;
case OP_FPA_INTERNAL_MAX_UNSPECIFIED: name = "fp.max_unspecified"; break;
default:
UNREACHABLE();
break;
@ -676,10 +672,10 @@ func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters,
return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k));
}
func_decl * fpa_decl_plugin::mk_internal_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters,
func_decl * fpa_decl_plugin::mk_bv2rm(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 internal_rm");
m_manager->raise_exception("invalid number of arguments to bv2rm");
if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) || domain[0]->get_parameter(0).get_int() != 3)
m_manager->raise_exception("sort mismatch, expected argument of sort bitvector, size 3");
if (!is_rm_sort(range))
@ -690,7 +686,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv2rm(decl_kind k, unsigned num_paramet
return m_manager->mk_func_decl(symbol("rm"), 1, &bv_srt, range, func_decl_info(m_family_id, k, num_parameters, parameters));
}
func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
func_decl * fpa_decl_plugin::mk_bv_wrap(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 bv_wrap");
@ -711,65 +707,6 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param
}
}
func_decl * fpa_decl_plugin::mk_internal_to_ubv_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 fp.to_ubv_unspecified");
if (num_parameters != 3)
m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 3");
if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting 3 integers");
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, &parameters[2]);
return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
func_decl * fpa_decl_plugin::mk_internal_to_sbv_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 fp.to_sbv_unspecified");
if (num_parameters != 3)
m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 3");
if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting 3 integers");
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, &parameters[2]);
return m_manager->mk_func_decl(symbol("fp.to_sbv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
func_decl * fpa_decl_plugin::mk_internal_to_real_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 fp.to_real_unspecified");
if (num_parameters != 2)
m_manager->raise_exception("invalid number of parameters to fp.to_real_unspecified; expecting 2");
if (!parameters[0].is_int() || !parameters[1].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_real_unspecified; expecting 2 integers");
if (!is_sort_of(range, m_arith_fid, REAL_SORT))
m_manager->raise_exception("sort mismatch, expected range of Real sort");
return m_manager->mk_func_decl(symbol("fp.to_real_unspecified"), 0, domain, m_real_sort, func_decl_info(m_family_id, k, num_parameters, parameters));
}
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 fp.to_ieee_bv_unspecified; expecting none");
if (num_parameters != 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 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("fp.to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
switch (k) {
@ -835,25 +772,11 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_FPA_TO_IEEE_BV:
return mk_to_ieee_bv(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_BVWRAP:
return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_BV2RM:
return mk_internal_bv2rm(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_BVWRAP:
return mk_bv_wrap(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_BV2RM:
return mk_bv2rm(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_MIN_I:
case OP_FPA_INTERNAL_MAX_I:
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
case OP_FPA_INTERNAL_MAX_UNSPECIFIED:
return mk_binary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
return mk_internal_to_real_unspecified(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
return mk_internal_to_ieee_bv_unspecified(k, num_parameters, parameters, arity, domain, range);
default:
m_manager->raise_exception("unsupported floating point operator");
return 0;
@ -1054,30 +977,6 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) {
return mk_value(v);
}
app * fpa_util::mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) };
sort * range = m_bv_util.mk_sort(width);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 3, ps, 0, 0, range);
}
app * fpa_util::mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) };
sort * range = m_bv_util.mk_sort(width);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 3, ps, 0, 0, range);
}
app * fpa_util::mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) {
parameter ps[] = { parameter(ebits), parameter(sbits) };
sort * range = m_bv_util.mk_sort(ebits+sbits);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, 2, ps, 0, 0, range);
}
app * fpa_util::mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits) {
parameter ps[] = { parameter(ebits), parameter(sbits) };
sort * range = m_a_util.mk_real();
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 2, ps, 0, 0, range);
}
bool fpa_util::contains_floats(ast * a) {
switch (a->get_kind()) {
case AST_APP: {

View file

@ -86,18 +86,8 @@ enum fpa_op_kind {
/* Extensions */
OP_FPA_TO_IEEE_BV,
/* Internal use only */
OP_FPA_INTERNAL_BVWRAP,
OP_FPA_INTERNAL_BV2RM,
OP_FPA_INTERNAL_MIN_I,
OP_FPA_INTERNAL_MAX_I,
OP_FPA_INTERNAL_MIN_UNSPECIFIED,
OP_FPA_INTERNAL_MAX_UNSPECIFIED,
OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED,
OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED,
OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED,
OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED,
OP_FPA_BVWRAP,
OP_FPA_BV2RM,
LAST_FLOAT_OP
};
@ -164,40 +154,16 @@ class fpa_decl_plugin : public decl_plugin {
func_decl * mk_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters,
func_decl * mk_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_to_ubv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_to_sbv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_to_real_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_internal_to_ieee_bv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
func_decl * mk_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual void set_manager(ast_manager * m, family_id id);
unsigned mk_id(mpf const & v);
void recycled_id(unsigned id);
virtual bool is_considered_uninterpreted(func_decl * f) {
if (f->get_family_id() != get_family_id())
return false;
switch (f->get_decl_kind())
{
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
return true;
default:
return false;
}
return false;
}
virtual bool is_considered_uninterpreted(func_decl * f) { return false; }
public:
fpa_decl_plugin();
@ -251,6 +217,7 @@ public:
family_id get_fid() const { return m_fid; }
family_id get_family_id() const { return m_fid; }
arith_util & au() { return m_a_util; }
bv_util & bu() { return m_bv_util; }
fpa_decl_plugin & plugin() { return *m_plugin; }
sort * mk_float_sort(unsigned ebits, unsigned sbits);
@ -375,35 +342,18 @@ public:
app * mk_bv2rm(expr * bv3) {
SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3);
return m().mk_app(m_fid, OP_FPA_INTERNAL_BV2RM, 0, 0, 1, &bv3, mk_rm_sort());
return m().mk_app(m_fid, OP_FPA_BV2RM, 0, 0, 1, &bv3, mk_rm_sort());
}
app * mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
app * mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
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 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_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BVWRAP); }
bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BV2RM); }
bool is_to_ubv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_UBV); }
bool is_to_sbv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_SBV); }
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 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 is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BVWRAP; }
bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BV2RM; }
bool is_to_ubv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_UBV; }
bool is_to_sbv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_SBV; }
bool contains_floats(ast * a);
};

View file

@ -244,7 +244,7 @@ struct pull_quant::imp {
quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr);
proof * p1 = 0;
if (n != q1) {
proof * p0 = m_manager.mk_pull_quant(to_quantifier(n)->get_expr(), to_quantifier(new_expr));
proof * p0 = m_manager.mk_pull_quant(n, to_quantifier(new_expr));
p1 = m_manager.mk_quant_intro(to_quantifier(n), q1, p0);
}
proof * p2 = q1 == r ? 0 : m_manager.mk_pull_quant(q1, to_quantifier(r));

View file

@ -56,7 +56,6 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
bool m_anum_simp;
bool m_elim_rem;
bool m_eq2ineq;
bool m_process_all_eqs;
unsigned m_max_degree;
void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts);

View file

@ -94,21 +94,8 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case OP_FPA_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(f, args[0], result); break;
case OP_FPA_TO_REAL: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break;
case OP_FPA_INTERNAL_MIN_I:
case OP_FPA_INTERNAL_MAX_I:
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;
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
st = BR_FAILED;
break;
case OP_FPA_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break;
case OP_FPA_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break;
default:
NOT_IMPLEMENTED_YET();
@ -116,49 +103,10 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
return st;
}
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) {
// The "hardware interpretation" is 0.
result = bu.mk_numeral(0, width);
return BR_DONE;
}
else {
result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
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) {
// The "hardware interpretation" is 0.
result = bu.mk_numeral(0, width);
return BR_DONE;
}
else {
result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
return BR_REWRITE1;
}
}
br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) {
if (m_hi_fp_unspecified) {
// The "hardware interpretation" is 0.
result = m_util.au().mk_numeral(rational(0), false);
return BR_DONE;
}
else {
result = m_util.mk_internal_to_real_unspecified(ebits, sbits);
return BR_REWRITE1;
}
}
br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_num_parameters() == 2);
SASSERT(f->get_parameter(0).is_int());
SASSERT(f->get_parameter(1).is_int());
bv_util bu(m());
scoped_mpf v(m_fm);
mpf_rounding_mode rmv;
rational r1, r2, r3;
@ -167,7 +115,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
unsigned sbits = f->get_parameter(1).get_int();
if (num_args == 1) {
if (bu.is_numeral(args[0], r1, bvs1)) {
if (m_util.bu().is_numeral(args[0], r1, bvs1)) {
// BV -> float
SASSERT(bvs1 == sbits + ebits);
unsynch_mpz_manager & mpzm = m_fm.mpz_manager();
@ -226,10 +174,10 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
// TRACE("fp_rewriter", tout << "result: " << result << std::endl; );
return BR_DONE;
}
else if (bu.is_numeral(args[1], r1, bvs1)) {
else if (m_util.bu().is_numeral(args[1], r1, bvs1)) {
// rm + signed bv -> float
TRACE("fp_rewriter", tout << "r1: " << r1 << std::endl;);
r1 = bu.norm(r1, bvs1, true);
r1 = m_util.bu().norm(r1, bvs1, true);
TRACE("fp_rewriter", tout << "r1 norm: " << r1 << std::endl;);
m_fm.set(v, ebits, sbits, rmv, r1.to_mpq());
result = m_util.mk_value(v);
@ -265,9 +213,9 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
result = m_util.mk_value(v);
return BR_DONE;
}
else if (bu.is_numeral(args[0], r1, bvs1) &&
bu.is_numeral(args[1], r2, bvs2) &&
bu.is_numeral(args[2], r3, bvs3)) {
else if (m_util.bu().is_numeral(args[0], r1, bvs1) &&
m_util.bu().is_numeral(args[1], r2, bvs2) &&
m_util.bu().is_numeral(args[2], r3, bvs3)) {
// 3 BV -> float
SASSERT(m_fm.mpz_manager().is_one(r2.to_mpq().denominator()));
SASSERT(m_fm.mpz_manager().is_one(r3.to_mpq().denominator()));
@ -290,7 +238,6 @@ br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg
SASSERT(f->get_num_parameters() == 2);
SASSERT(f->get_parameter(0).is_int());
SASSERT(f->get_parameter(1).is_int());
bv_util bu(m());
unsigned ebits = f->get_parameter(0).get_int();
unsigned sbits = f->get_parameter(1).get_int();
mpf_rounding_mode rmv;
@ -298,7 +245,7 @@ br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg
unsigned bvs;
if (m_util.is_rm_numeral(arg1, rmv) &&
bu.is_numeral(arg2, r, bvs)) {
m_util.bu().is_numeral(arg2, r, bvs)) {
scoped_mpf v(m_fm);
m_fm.set(v, ebits, sbits, rmv, r.to_mpq());
result = m_util.mk_value(v);
@ -331,6 +278,7 @@ br_status fpa_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref &
br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm_numeral(arg1, rm)) {
scoped_mpf v2(m_fm), v3(m_fm);
if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) {
@ -346,6 +294,7 @@ br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref &
br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm_numeral(arg1, rm)) {
scoped_mpf v2(m_fm), v3(m_fm);
if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) {
@ -355,7 +304,6 @@ br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref &
return BR_DONE;
}
}
return BR_FAILED;
}
@ -393,6 +341,7 @@ br_status fpa_rewriter::mk_neg(expr * arg1, expr_ref & result) {
br_status fpa_rewriter::mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
scoped_mpf t(m_fm);
m_fm.rem(v1, v2, t);
@ -431,27 +380,16 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) {
result = m().mk_app(get_fid(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, arg1, arg2);
return BR_REWRITE1;
}
else {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2))
return BR_FAILED;
scoped_mpf r(m_fm);
m_fm.minimum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE;
}
}
else {
expr_ref c(m()), v(m());
c = m().mk_and(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)),
m().mk_or(m().mk_and(m_util.mk_is_positive(arg1), m_util.mk_is_negative(arg2)),
m().mk_and(m_util.mk_is_negative(arg1), m_util.mk_is_positive(arg2))));
v = m().mk_app(get_fid(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, arg1, arg2);
result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_INTERNAL_MIN_I, arg1, arg2));
return BR_REWRITE_FULL;
}
return BR_FAILED;
}
br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) {
@ -466,31 +404,21 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) {
result = m().mk_app(get_fid(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, arg1, arg2);
return BR_REWRITE1;
}
else {
if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2))
return BR_FAILED;
scoped_mpf r(m_fm);
m_fm.maximum(v1, v2, r);
result = m_util.mk_value(r);
return BR_DONE;
}
}
else {
expr_ref c(m()), v(m());
c = m().mk_and(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)),
m().mk_or(m().mk_and(m_util.mk_is_positive(arg1), m_util.mk_is_negative(arg2)),
m().mk_and(m_util.mk_is_negative(arg1), m_util.mk_is_positive(arg2))));
v = m().mk_app(get_fid(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, arg1, arg2);
result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_INTERNAL_MAX_I, arg1, arg2));
return BR_REWRITE_FULL;
}
return BR_FAILED;
}
br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm_numeral(arg1, rm)) {
scoped_mpf v2(m_fm), v3(m_fm), v4(m_fm);
if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3) && m_util.is_numeral(arg4, v4)) {
@ -506,6 +434,7 @@ br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg
br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm_numeral(arg1, rm)) {
scoped_mpf v2(m_fm);
if (m_util.is_numeral(arg2, v2)) {
@ -521,6 +450,7 @@ br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) {
br_status fpa_rewriter::mk_round_to_integral(expr * arg1, expr * arg2, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm_numeral(arg1, rm)) {
scoped_mpf v2(m_fm);
if (m_util.is_numeral(arg2, v2)) {
@ -588,7 +518,6 @@ br_status fpa_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
return BR_DONE;
}
// TODO: more simplifications
return BR_FAILED;
}
@ -652,6 +581,7 @@ br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) {
br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) {
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg1, v)) {
result = (m_fm.is_nan(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
@ -662,6 +592,7 @@ br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) {
br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) {
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg1, v)) {
result = (m_fm.is_inf(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
@ -672,6 +603,7 @@ br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) {
br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) {
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg1, v)) {
result = (m_fm.is_normal(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
@ -682,6 +614,7 @@ br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) {
br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) {
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg1, v)) {
result = (m_fm.is_denormal(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
@ -692,6 +625,7 @@ br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) {
br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) {
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg1, v)) {
result = (m_fm.is_neg(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
@ -702,6 +636,7 @@ br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) {
br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) {
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg1, v)) {
result = (m_fm.is_neg(v) || m_fm.is_nan(v)) ? m().mk_false() : m().mk_true();
return BR_DONE;
@ -714,6 +649,7 @@ br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) {
// This the SMT =
br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_fm), v2(m_fm);
if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
// Note: == is the floats-equality, here we need normal equality.
result = (m_fm.is_nan(v1) && m_fm.is_nan(v2)) ? m().mk_true() :
@ -727,10 +663,10 @@ br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result)
}
br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) {
bv_util bu(m());
rational bv_val;
unsigned sz = 0;
if (bu.is_numeral(arg, bv_val, sz)) {
if (m_util.bu().is_numeral(arg, bv_val, sz)) {
SASSERT(bv_val.is_uint64());
switch (bv_val.get_uint64()) {
case BV_RM_TIES_TO_AWAY: result = m_util.mk_round_nearest_ties_to_away(); break;
@ -749,13 +685,12 @@ br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) {
br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result) {
unsynch_mpz_manager & mpzm = m_fm.mpz_manager();
bv_util bu(m());
rational rsgn, rexp, rsig;
unsigned bvsz_sgn, bvsz_exp, bvsz_sig;
if (bu.is_numeral(sgn, rsgn, bvsz_sgn) &&
bu.is_numeral(sig, rsig, bvsz_sig) &&
bu.is_numeral(exp, rexp, bvsz_exp)) {
if (m_util.bu().is_numeral(sgn, rsgn, bvsz_sgn) &&
m_util.bu().is_numeral(sig, rsig, bvsz_sig) &&
m_util.bu().is_numeral(exp, rexp, bvsz_exp)) {
SASSERT(mpzm.is_one(rexp.to_mpq().denominator()));
SASSERT(mpzm.is_one(rsig.to_mpq().denominator()));
scoped_mpf v(m_fm);
@ -772,7 +707,7 @@ br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & res
return BR_FAILED;
}
br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) {
br_status fpa_rewriter::mk_to_bv(func_decl * f, expr * arg1, expr * arg2, bool is_signed, expr_ref & result) {
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_int());
int bv_sz = f->get_parameter(0).get_int();
@ -781,10 +716,9 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
if (m_util.is_rm_numeral(arg1, rmv) &&
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))
return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
if (m_fm.is_nan(v) || m_fm.is_inf(v))
return mk_to_bv_unspecified(f, result);
bv_util bu(m());
scoped_mpq q(m_fm.mpq_manager());
@ -792,51 +726,41 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
rational r(q);
rational ul, ll;
if (!is_signed) {
ul = m_fm.m_powers2.m1(bv_sz);
ll = rational(0);
}
else {
ul = m_fm.m_powers2.m1(bv_sz - 1);
ll = -m_fm.m_powers2(bv_sz - 1);
}
if (r >= ll && r <= ul) {
result = bu.mk_numeral(r, bv_sz);
return BR_DONE;
}
else
return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return mk_to_bv_unspecified(f, result);
}
return BR_FAILED;
}
br_status fpa_rewriter::mk_to_bv_unspecified(func_decl * f, expr_ref & result) {
if (m_hi_fp_unspecified) {
unsigned bv_sz = m_util.bu().get_bv_size(f->get_range());
result = m_util.bu().mk_numeral(0, bv_sz);
return BR_DONE;
}
else
return BR_FAILED;
}
br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) {
return mk_to_bv(f, arg1, arg2, false, result);
}
br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) {
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_int());
int bv_sz = f->get_parameter(0).get_int();
mpf_rounding_mode rmv;
scoped_mpf v(m_fm);
if (m_util.is_rm_numeral(arg1, rmv) &&
m_util.is_numeral(arg2, v)) {
const mpf & x = v.get();
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());
m_fm.to_sbv_mpq(rmv, v, q);
rational r(q);
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) {
result = bu.mk_numeral(r, bv_sz);
return BR_DONE;
}
else
return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
}
return BR_FAILED;
return mk_to_bv(f, arg1, arg2, true, result);
}
br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result) {
@ -855,12 +779,9 @@ br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & resu
bu.mk_numeral(0, x.get_sbits() - 2),
bu.mk_numeral(1, 1) };
result = bu.mk_concat(4, args);
}
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);
@ -877,16 +798,18 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) {
if (m_util.is_numeral(arg, v)) {
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
const mpf & x = v.get();
result = m_util.mk_internal_to_real_unspecified(x.get_ebits(), x.get_sbits());
if (m_hi_fp_unspecified) {
result = m_util.au().mk_numeral(rational(0), false);
return BR_DONE;
}
}
else {
scoped_mpq r(m_fm.mpq_manager());
m_fm.to_rational(v, r);
result = m_util.au().mk_numeral(r.get(), false);
}
return BR_DONE;
}
}
return BR_FAILED;
}

View file

@ -21,8 +21,9 @@ Notes:
#include "ast/ast.h"
#include "ast/rewriter/rewriter.h"
#include "util/params.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/expr_map.h"
#include "util/params.h"
#include "util/mpf.h"
class fpa_rewriter {
@ -33,6 +34,9 @@ class fpa_rewriter {
app * mk_eq_nan(expr * arg);
app * mk_neq_nan(expr * arg);
br_status mk_to_bv(func_decl * f, expr * arg1, expr * arg2, bool is_signed, expr_ref & result);
br_status mk_to_bv_unspecified(func_decl * f, expr_ref & result);
public:
fpa_rewriter(ast_manager & m, params_ref const & p = params_ref());
~fpa_rewriter();
@ -73,22 +77,17 @@ public:
br_status mk_is_negative(expr * arg1, expr_ref & result);
br_status mk_is_positive(expr * arg1, expr_ref & result);
br_status mk_to_ieee_bv(expr * arg1, expr_ref & result);
br_status mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv2rm(expr * arg, expr_ref & result);
br_status mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result);
br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
br_status mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
br_status mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result);
br_status mk_to_real(expr * arg, expr_ref & result);
br_status mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result);
br_status mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result);
br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result);
br_status mk_min_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
br_status mk_max_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bvwrap(expr * arg, expr_ref & result);
};

View file

@ -686,7 +686,7 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args,
return BR_DONE;
}
set_curr_sort(m().get_sort(args[0]));
expr * minus_one = mk_numeral(numeral(-1));
expr_ref minus_one(mk_numeral(numeral(-1)), m());
ptr_buffer<expr> new_args;
new_args.push_back(args[0]);
for (unsigned i = 1; i < num_args; i++) {
@ -1010,7 +1010,6 @@ bool poly_rewriter<Config>::is_var_plus_ground(expr * n, bool & inv, var * & v,
stop = true;
}
if (is_ground(arg)) {
TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m()) << "\n";);
args.push_back(arg);
}
else if (is_var(arg)) {

View file

@ -42,6 +42,10 @@ void rewriter_tpl<Config>::process_var(var * v) {
unsigned index = m_bindings.size() - idx - 1;
var * r = (var*)(m_bindings[index]);
if (r != 0) {
CTRACE("rewriter", v->get_sort() != m().get_sort(r),
tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m());
tout << "index " << index << " bindings " << m_bindings.size() << "\n";
display_bindings(tout););
SASSERT(v->get_sort() == m().get_sort(r));
if (!is_ground(r) && m_shifts[index] != m_bindings.size()) {

View file

@ -736,7 +736,6 @@ ast_manager & th_rewriter::m() const {
void th_rewriter::updt_params(params_ref const & p) {
m_params = p;
m_imp->cfg().updt_params(p);
IF_VERBOSE(10, verbose_stream() << p << "\n";);
}
void th_rewriter::get_param_descrs(param_descrs & r) {

View file

@ -37,6 +37,7 @@ struct check_logic::imp {
datatype_util m_dt_util;
pb_util m_pb_util;
bool m_uf; // true if the logic supports uninterpreted functions
bool m_dt; // true if the lgoic supports dattypes
bool m_arrays; // true if the logic supports arbitrary arrays
bool m_bv_arrays; // true if the logic supports only bv arrays
bool m_reals; // true if the logic supports reals
@ -53,6 +54,7 @@ struct check_logic::imp {
void reset() {
m_uf = false;
m_dt = false;
m_arrays = false;
m_bv_arrays = false;
m_reals = false;
@ -105,6 +107,10 @@ struct check_logic::imp {
m_uf = true;
m_bvs = true;
}
else if (logic == "QF_DT") {
m_uf = true;
m_dt = true;
}
else if (logic == "QF_AUFLIA") {
m_uf = true;
m_arrays = true;
@ -187,6 +193,7 @@ struct check_logic::imp {
m_bvs = true;
m_uf = true;
m_ints = true;
m_dt = true;
m_nonlinear = true; // non-linear 0-1 variables may get eliminated
}
else {
@ -443,7 +450,7 @@ 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") {
else if (fid == m_dt_util.get_family_id() && m_dt) {
// nothing to check
}
else if (fid == m_pb_util.get_family_id() && m_logic == "QF_FD") {

View file

@ -202,7 +202,7 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range
if (f->get_arity() != arity)
continue;
unsigned i = 0;
for (i = 0; i < arity; i++) {
for (i = 0; domain && i < arity; i++) {
if (f->get_domain(i) != domain[i])
break;
}
@ -937,7 +937,7 @@ static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family
func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices,
unsigned arity, sort * const * domain, sort * range) const {
builtin_decl d;
if (m_builtin_decls.find(s, d)) {
if (domain && m_builtin_decls.find(s, d)) {
family_id fid = d.m_fid;
decl_kind k = d.m_decl;
// Hack: if d.m_next != 0, we use domain[0] (if available) to decide which plugin we use.
@ -961,7 +961,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices,
return f;
}
if (contains_macro(s, arity, domain))
if (domain && contains_macro(s, arity, domain))
throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s);
if (num_indices > 0)
@ -1545,6 +1545,26 @@ void cmd_context::reset_assertions() {
}
void cmd_context::display_dimacs() {
if (m_solver) {
try {
gparams::set("sat.dimacs.display", "true");
params_ref p;
m_solver->updt_params(p);
m_solver->check_sat(0, nullptr);
}
catch (...) {
gparams::set("sat.dimacs.display", "false");
params_ref p;
m_solver->updt_params(p);
throw;
}
gparams::set("sat.dimacs.display", "false");
params_ref p;
m_solver->updt_params(p);
}
}
void cmd_context::display_model(model_ref& mdl) {
if (mdl) {
model_params p;
@ -1609,12 +1629,16 @@ void cmd_context::set_diagnostic_stream(char const * name) {
}
}
struct contains_array_op_proc {
struct contains_underspecified_op_proc {
struct found {};
family_id m_array_fid;
contains_array_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")) {}
datatype_util m_dt;
contains_underspecified_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")), m_dt(m) {}
void operator()(var * n) {}
void operator()(app * n) {
if (m_dt.is_accessor(n->get_decl()))
throw found();
if (n->get_family_id() != m_array_fid)
return;
decl_kind k = n->get_decl_kind();
@ -1665,6 +1689,16 @@ void cmd_context::complete_model() {
}
}
for (unsigned i = 0; i < md->get_num_functions(); i++) {
func_decl * f = md->get_function(i);
func_interp * fi = md->get_func_interp(f);
IF_VERBOSE(12, verbose_stream() << "(model.completion " << f->get_name() << ")\n"; );
if (fi->is_partial()) {
sort * range = f->get_range();
fi->set_else(m().get_some_value(range));
}
}
for (auto kd : m_func_decls) {
symbol const & k = kd.m_key;
func_decls & v = kd.m_value;
@ -1703,7 +1737,7 @@ void cmd_context::validate_model() {
p.set_bool("completion", true);
model_evaluator evaluator(*(md.get()), p);
evaluator.set_expand_array_equalities(false);
contains_array_op_proc contains_array(m());
contains_underspecified_op_proc contains_underspecified(m());
{
scoped_rlimit _rlimit(m().limit(), 0);
cancel_eh<reslimit> eh(m().limit());
@ -1729,9 +1763,9 @@ void cmd_context::validate_model() {
continue;
}
try {
for_each_expr(contains_array, r);
for_each_expr(contains_underspecified, r);
}
catch (contains_array_op_proc::found) {
catch (contains_underspecified_op_proc::found) {
continue;
}
TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0););

View file

@ -419,6 +419,7 @@ public:
void display_assertions();
void display_statistics(bool show_total_time = false, double total_time = 0.0);
void display_dimacs();
void reset(bool finalize = false);
void assert_expr(expr * t);
void assert_expr(symbol const & name, expr * t);

View file

@ -31,7 +31,6 @@ Notes:
#include "ast/rewriter/var_subst.h"
#include "util/gparams.h"
#ifndef _EXTERNAL_RELEASE
BINARY_SYM_CMD(get_quantifier_body_cmd,
"dbg-get-qbody",
@ -343,10 +342,19 @@ public:
}
};
#endif
class print_dimacs_cmd : public cmd {
public:
print_dimacs_cmd():cmd("display-dimacs") {}
virtual char const * get_usage() const { return ""; }
virtual char const * get_descr(cmd_context & ctx) const { return "print benchmark in DIMACS format"; }
virtual unsigned get_arity() const { return 0; }
virtual void prepare(cmd_context & ctx) {}
virtual void execute(cmd_context & ctx) { ctx.display_dimacs(); }
};
void install_dbg_cmds(cmd_context & ctx) {
#ifndef _EXTERNAL_RELEASE
ctx.insert(alloc(print_dimacs_cmd));
ctx.insert(alloc(get_quantifier_body_cmd));
ctx.insert(alloc(set_cmd));
ctx.insert(alloc(pp_var_cmd));
@ -369,5 +377,4 @@ void install_dbg_cmds(cmd_context & ctx) {
ctx.insert(alloc(instantiate_cmd));
ctx.insert(alloc(instantiate_nested_cmd));
ctx.insert(alloc(set_next_id));
#endif
}

View file

@ -197,6 +197,9 @@ public:
}
virtual void execute(cmd_context & ctx) {
if (!m_tactic) {
throw cmd_exception("check-sat-using needs a tactic argument");
}
params_ref p = ctx.params().merge_default_params(ps());
tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p);
tref->set_logic(ctx.get_logic());

View file

@ -21,6 +21,7 @@
#pragma once
#include "duality/duality_wrapper.h"
#include <vector>
#include <list>
#include <map>

View file

@ -930,7 +930,6 @@ namespace Duality {
#endif
// expr proof() const { Z3_ast r = Z3_solver_proof(ctx(), m_solver); check_error(); return expr(ctx(), r); }
// friend std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; }
int get_num_decisions();
void cancel(){

View file

@ -41,8 +41,6 @@ class boolean_algebra : public positive_boolean_algebra<T> {
public:
virtual ~boolean_algebra() {}
virtual T mk_not(T x) = 0;
//virtual lbool are_equivalent(T x, T y) = 0;
//virtual T simplify(T x) = 0;
};
#endif

View file

@ -451,8 +451,16 @@ typename symbolic_automata<T, M>::automaton_t* symbolic_automata<T, M>::mk_produ
}
}
if (mvs1.empty()) {
if (a.is_final_state(a.init()) && b.is_final_state(b.init())) {
// special case: automaton has no moves, but the initial state is final on both sides
// this results in the automaton which accepts the empty sequence and nothing else
final.clear();
final.push_back(0);
return alloc(automaton_t, m, 0, final, mvs1);
} else {
return alloc(automaton_t, m);
}
}
else {
return alloc(automaton_t, m, 0, final, mvs1);
}

View file

@ -140,7 +140,6 @@ void func_interp::set_else(expr * e) {
return;
reset_interp_cache();
ptr_vector<expr> args;
while (e && is_fi_entry_expr(e, args)) {
TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;);

View file

@ -33,9 +33,11 @@ Revision History:
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "model/model_smt2_pp.h"
#include "ast/rewriter/var_subst.h"
struct evaluator_cfg : public default_rewriter_cfg {
ast_manager & m;
model_core & m_model;
bool_rewriter m_b_rw;
arith_rewriter m_a_rw;
@ -53,6 +55,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
bool m_array_equalities;
evaluator_cfg(ast_manager & m, model_core & md, params_ref const & p):
m(m),
m_model(md),
m_b_rw(m),
// We must allow customers to set parameters for arithmetic rewriter/evaluator.
@ -74,6 +77,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
m_ar_rw.set_expand_select_store(true);
m_ar_rw.set_expand_select_ite(true);
updt_params(p);
//add_unspecified_function_models(md);
}
void updt_params(params_ref const & _p) {
@ -85,8 +89,6 @@ struct evaluator_cfg : public default_rewriter_cfg {
m_array_equalities = p.array_equalities();
}
ast_manager & m() const { return m_model.get_manager(); }
bool evaluate(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
func_interp * fi = m_model.get_func_interp(f);
return (fi != 0) && eval_fi(fi, num, args, result);
@ -101,9 +103,8 @@ struct evaluator_cfg : public default_rewriter_cfg {
bool actuals_are_values = true;
for (unsigned i = 0; actuals_are_values && i < num; i++) {
actuals_are_values = m().is_value(args[i]);
}
for (unsigned i = 0; actuals_are_values && i < num; i++)
actuals_are_values = m.is_value(args[i]);
if (!actuals_are_values)
return false; // let get_macro handle it
@ -120,7 +121,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
family_id fid = f->get_family_id();
bool is_uninterp = fid != null_family_id && m().get_plugin(fid)->is_considered_uninterpreted(f);
bool is_uninterp = fid != null_family_id && m.get_plugin(fid)->is_considered_uninterpreted(f);
if (num == 0 && (fid == null_family_id || is_uninterp)) {
expr * val = m_model.get_const_interp(f);
if (val != 0) {
@ -145,7 +146,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
if (k == OP_EQ) {
// theory dispatch for =
SASSERT(num == 2);
family_id s_fid = m().get_sort(args[0])->get_family_id();
family_id s_fid = m.get_sort(args[0])->get_family_id();
if (s_fid == m_a_rw.get_fid())
st = m_a_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_bv_rw.get_fid())
@ -178,16 +179,18 @@ struct evaluator_cfg : public default_rewriter_cfg {
st = m_f_rw.mk_app_core(f, num, args, result);
else if (fid == m_seq_rw.get_fid())
st = m_seq_rw.mk_app_core(f, num, args, result);
else if (fid == m().get_label_family_id() && num == 1) {
else if (fid == m.get_label_family_id() && num == 1) {
result = args[0];
st = BR_DONE;
}
else if (evaluate(f, num, args, result)) {
TRACE("model_evaluator", tout << "reduce_app " << f->get_name() << "\n";
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";
tout << "---->\n" << mk_ismt2_pp(result, m()) << "\n";);
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m) << "\n";
tout << "---->\n" << mk_ismt2_pp(result, m) << "\n";);
return BR_DONE;
}
if (st == BR_FAILED && !m.is_builtin_family_id(fid))
st = evaluate_partial_theory_func(f, num, args, result, result_pr);
if (st == BR_DONE && is_app(result)) {
app* a = to_app(result);
if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) {
@ -200,14 +203,14 @@ struct evaluator_cfg : public default_rewriter_cfg {
void expand_value(expr_ref& val) {
vector<expr_ref_vector> stores;
expr_ref else_case(m());
expr_ref else_case(m);
bool _unused;
if (m_ar.is_array(val) && extract_array_func_interp(val, stores, else_case, _unused)) {
sort* srt = m().get_sort(val);
sort* srt = m.get_sort(val);
val = m_ar.mk_const_array(srt, else_case);
for (unsigned i = stores.size(); i > 0; ) {
--i;
expr_ref_vector args(m());
expr_ref_vector args(m);
args.push_back(val);
args.append(stores[i].size(), stores[i].c_ptr());
val = m_ar.mk_store(args.size(), args.c_ptr());
@ -220,6 +223,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
#define TRACE_MACRO TRACE("model_evaluator", tout << "get_macro for " << f->get_name() << " (model completion: " << m_model_completion << ")\n";);
func_interp * fi = m_model.get_func_interp(f);
if (fi != 0) {
TRACE_MACRO;
if (fi->is_partial()) {
@ -228,10 +232,9 @@ struct evaluator_cfg : public default_rewriter_cfg {
expr * val = m_model.get_some_value(s);
fi->set_else(val);
}
else {
else
return false;
}
}
def = fi->get_interp();
SASSERT(def != 0);
return true;
@ -239,20 +242,42 @@ struct evaluator_cfg : public default_rewriter_cfg {
if (m_model_completion &&
(f->get_family_id() == null_family_id ||
m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f)))
m.get_plugin(f->get_family_id())->is_considered_uninterpreted(f)))
{
TRACE_MACRO;
sort * s = f->get_range();
expr * val = m_model.get_some_value(s);
func_interp * new_fi = alloc(func_interp, m(), f->get_arity());
func_interp * new_fi = alloc(func_interp, m, f->get_arity());
new_fi->set_else(val);
m_model.register_decl(f, new_fi);
def = val;
return true;
}
return false;
}
br_status evaluate_partial_theory_func(func_decl * f,
unsigned num, expr * const * args,
expr_ref & result, proof_ref & result_pr) {
SASSERT(f != 0);
SASSERT(!m.is_builtin_family_id(f->get_family_id()));
result = 0;
result_pr = 0;
func_interp * fi = m_model.get_func_interp(f);
if (fi) {
if (fi->is_partial())
fi->set_else(m.get_some_value(f->get_range()));
var_subst vs(m, false);
vs(fi->get_interp(), num, args, result);
return BR_REWRITE_FULL;
}
return BR_FAILED;
}
bool max_steps_exceeded(unsigned num_steps) const {
cooperate("model evaluator");
@ -266,7 +291,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
br_status mk_array_eq(expr* a, expr* b, expr_ref& result) {
if (a == b) {
result = m().mk_true();
result = m.mk_true();
return BR_DONE;
}
if (!m_array_equalities) {
@ -275,19 +300,19 @@ struct evaluator_cfg : public default_rewriter_cfg {
vector<expr_ref_vector> stores1, stores2;
bool args_are_unique1, args_are_unique2;
expr_ref else1(m()), else2(m());
expr_ref else1(m), else2(m);
if (extract_array_func_interp(a, stores1, else1, args_are_unique1) &&
extract_array_func_interp(b, stores2, else2, args_are_unique2)) {
expr_ref_vector conj(m()), args1(m()), args2(m());
if (m().are_equal(else1, else2)) {
expr_ref_vector conj(m), args1(m), args2(m);
if (m.are_equal(else1, else2)) {
// no op
}
else if (m().are_distinct(else1, else2) && !(m().get_sort(else1)->get_info()->get_num_elements().is_finite())) {
result = m().mk_false();
else if (m.are_distinct(else1, else2) && !(m.get_sort(else1)->get_info()->get_num_elements().is_finite())) {
result = m.mk_false();
return BR_DONE;
}
else {
conj.push_back(m().mk_eq(else1, else2));
conj.push_back(m.mk_eq(else1, else2));
}
if (args_are_unique1 && args_are_unique2 && !stores1.empty()) {
return mk_array_eq_core(stores1, else1, stores2, else2, conj, result);
@ -300,11 +325,11 @@ struct evaluator_cfg : public default_rewriter_cfg {
for (unsigned i = 0; i < stores1.size(); ++i) {
args1.resize(1); args1.append(stores1[i].size() - 1, stores1[i].c_ptr());
args2.resize(1); args2.append(stores1[i].size() - 1, stores1[i].c_ptr());
expr_ref s1(m_ar.mk_select(args1.size(), args1.c_ptr()), m());
expr_ref s2(m_ar.mk_select(args2.size(), args2.c_ptr()), m());
conj.push_back(m().mk_eq(s1, s2));
expr_ref s1(m_ar.mk_select(args1.size(), args1.c_ptr()), m);
expr_ref s2(m_ar.mk_select(args2.size(), args2.c_ptr()), m);
conj.push_back(m.mk_eq(s1, s2));
}
result = m().mk_and(conj.size(), conj.c_ptr());
result = m.mk_and(conj.size(), conj.c_ptr());
return BR_REWRITE_FULL;
}
return BR_FAILED;
@ -362,15 +387,15 @@ struct evaluator_cfg : public default_rewriter_cfg {
if (table1.find(stores2[i].c_ptr(), args)) {
switch (compare(args[arity], val)) {
case l_true: table1.remove(args); break;
case l_false: result = m().mk_false(); return BR_DONE;
default: conj.push_back(m().mk_eq(val, args[arity])); break;
case l_false: result = m.mk_false(); return BR_DONE;
default: conj.push_back(m.mk_eq(val, args[arity])); break;
}
}
else {
switch (compare(else1, val)) {
case l_true: break;
case l_false: result = m().mk_false(); return BR_DONE;
default: conj.push_back(m().mk_eq(else1, val)); break;
case l_false: result = m.mk_false(); return BR_DONE;
default: conj.push_back(m.mk_eq(else1, val)); break;
}
}
}
@ -378,8 +403,8 @@ struct evaluator_cfg : public default_rewriter_cfg {
for (; it != end; ++it) {
switch (compare((*it)[arity], else2)) {
case l_true: break;
case l_false: result = m().mk_false(); return BR_DONE;
default: conj.push_back(m().mk_eq((*it)[arity], else2)); break;
case l_false: result = m.mk_false(); return BR_DONE;
default: conj.push_back(m.mk_eq((*it)[arity], else2)); break;
}
}
result = mk_and(conj);
@ -387,8 +412,8 @@ struct evaluator_cfg : public default_rewriter_cfg {
}
lbool compare(expr* a, expr* b) {
if (m().are_equal(a, b)) return l_true;
if (m().are_distinct(a, b)) return l_false;
if (m.are_equal(a, b)) return l_true;
if (m.are_distinct(a, b)) return l_false;
return l_undef;
}
@ -396,8 +421,8 @@ struct evaluator_cfg : public default_rewriter_cfg {
bool args_are_values(expr_ref_vector const& store, bool& are_unique) {
bool are_values = true;
for (unsigned j = 0; are_values && j + 1 < store.size(); ++j) {
are_values = m().is_value(store[j]);
are_unique &= m().is_unique_value(store[j]);
are_values = m.is_value(store[j]);
are_unique &= m.is_unique_value(store[j]);
}
SASSERT(!are_unique || are_values);
return are_values;
@ -408,10 +433,10 @@ struct evaluator_cfg : public default_rewriter_cfg {
SASSERT(m_ar.is_array(a));
bool are_values = true;
are_unique = true;
TRACE("model_evaluator", tout << mk_pp(a, m()) << "\n";);
TRACE("model_evaluator", tout << mk_pp(a, m) << "\n";);
while (m_ar.is_store(a)) {
expr_ref_vector store(m());
expr_ref_vector store(m);
store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1);
are_values &= args_are_values(store, are_unique);
stores.push_back(store);
@ -424,7 +449,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
}
if (!m_ar.is_as_array(a)) {
TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m()) << "\n";);
TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m) << "\n";);
return false;
}
@ -434,13 +459,13 @@ struct evaluator_cfg : public default_rewriter_cfg {
unsigned arity = f->get_arity();
unsigned base_sz = stores.size();
for (unsigned i = 0; i < sz; ++i) {
expr_ref_vector store(m());
expr_ref_vector store(m);
func_entry const* fe = g->get_entry(i);
store.append(arity, fe->get_args());
store.push_back(fe->get_result());
for (unsigned j = 0; j < store.size(); ++j) {
if (!is_ground(store[j].get())) {
TRACE("model_evaluator", tout << "could not extract array interpretation: " << mk_pp(a, m()) << "\n" << mk_pp(store[j].get(), m()) << "\n";);
TRACE("model_evaluator", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";);
return false;
}
}
@ -448,18 +473,18 @@ struct evaluator_cfg : public default_rewriter_cfg {
}
else_case = g->get_else();
if (!else_case) {
TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m()) << "\n";
/*model_smt2_pp(tout, m(), m_model, 0);*/
TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m) << "\n";
/*model_smt2_pp(tout, m, m_model, 0);*/
);
return false;
}
if (!is_ground(else_case)) {
TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m()) << "\n" << else_case << "\n";);
TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m) << "\n" << else_case << "\n";);
return false;
}
for (unsigned i = stores.size(); are_values && i > base_sz; ) {
--i;
if (m().are_equal(else_case, stores[i].back())) {
if (m.are_equal(else_case, stores[i].back())) {
for (unsigned j = i + 1; j < stores.size(); ++j) {
stores[j-1].reset();
stores[j-1].append(stores[j]);
@ -469,7 +494,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
}
are_values &= args_are_values(stores[i], are_unique);
}
TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m()) << "\n";);
TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m) << "\n";);
return true;
}

View file

@ -160,7 +160,7 @@ def_module_params('fixedpoint',
('xform.coalesce_rules', BOOL, False, "coalesce rules"),
('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"),
('xform.subsumption_checker', BOOL, True, "Enable subsumption checker (no support for model conversion)"),
('xform.coi', BOOL, True, "use cone of influence simplificaiton"),
('xform.coi', BOOL, True, "use cone of influence simplification"),
('duality.enable_restarts', BOOL, False, 'DUALITY: enable restarts'),
('spacer.order_children', UINT, 0, 'SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse)'),
('spacer.eager_reach_check', BOOL, True, 'SPACER: eagerly check if a query is reachable using reachability facts of predecessors'),

View file

@ -96,6 +96,9 @@ public:
}
virtual void execute(cmd_context & ctx) {
if (!m_formula) {
throw cmd_exception("assert-soft requires a formulas as argument.");
}
symbol w("weight");
rational weight = ps().get_rat(symbol("weight"), rational::one());
symbol id = ps().get_sym(symbol("id"), symbol::null);

View file

@ -24,6 +24,7 @@ Revision History:
#include "ast/ast_pp.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/rewriter.h"
#include "ast/rewriter/var_subst.h"
#include "ast/has_free_vars.h"
#include "ast/ast_smt2_pp.h"
#include "parsers/smt2/smt2parser.h"
@ -68,6 +69,7 @@ namespace smt2 {
scoped_ptr<bv_util> m_bv_util;
scoped_ptr<arith_util> m_arith_util;
scoped_ptr<datatype_util> m_datatype_util;
scoped_ptr<seq_util> m_seq_util;
scoped_ptr<pattern_validator> m_pattern_validator;
scoped_ptr<var_shifter> m_var_shifter;
@ -108,6 +110,7 @@ namespace smt2 {
symbol m_check_sat_assuming;
symbol m_define_fun_rec;
symbol m_define_funs_rec;
symbol m_match;
symbol m_underscore;
typedef std::pair<symbol, expr*> named_expr;
@ -135,7 +138,7 @@ namespace smt2 {
typedef psort_frame sort_frame;
enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN };
enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_MATCH, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN };
struct expr_frame {
expr_frame_kind m_kind;
@ -172,6 +175,10 @@ namespace smt2 {
m_expr_spos(expr_spos) {}
};
struct match_frame : public expr_frame {
match_frame():expr_frame(EF_MATCH) {}
};
struct let_frame : public expr_frame {
bool m_in_decls;
unsigned m_sym_spos;
@ -275,6 +282,12 @@ namespace smt2 {
return *(m_arith_util.get());
}
datatype_util & dtutil() {
if (m_datatype_util.get() == 0)
m_datatype_util = alloc(datatype_util, m());
return *(m_datatype_util.get());
}
seq_util & sutil() {
if (m_seq_util.get() == 0)
m_seq_util = alloc(seq_util, m());
@ -389,6 +402,7 @@ namespace smt2 {
bool curr_id_is_underscore() const { SASSERT(curr_is_identifier()); return curr_id() == m_underscore; }
bool curr_id_is_as() const { SASSERT(curr_is_identifier()); return curr_id() == m_as; }
bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; }
bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; }
bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; }
bool curr_id_is_bang() const { SASSERT(curr_is_identifier()); return curr_id() == m_bang; }
@ -1258,6 +1272,23 @@ namespace smt2 {
return num;
}
void push_let_frame() {
next();
check_lparen_next("invalid let declaration, '(' expected");
void * mem = m_stack.allocate(sizeof(let_frame));
new (mem) let_frame(symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
}
void push_bang_frame(expr_frame * curr) {
TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";);
next();
void * mem = m_stack.allocate(sizeof(attr_expr_frame));
new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
}
void push_quant_frame(bool is_forall) {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_forall() || curr_id_is_exists());
@ -1273,6 +1304,202 @@ namespace smt2 {
throw parser_exception("invalid quantifier, list of sorted variables is empty");
}
/**
* SMT-LIB 2.6 pattern matches are of the form
* (match t ((p1 t1) ... (pm+1 tm+1)))
*/
void push_match_frame() {
SASSERT(curr_is_identifier());
SASSERT(curr_id() == m_match);
next();
void * mem = m_stack.allocate(sizeof(match_frame));
new (mem) match_frame();
unsigned num_frames = m_num_expr_frames;
parse_expr();
expr_ref t(expr_stack().back(), m());
expr_stack().pop_back();
expr_ref_vector patterns(m()), cases(m());
sort* srt = m().get_sort(t);
check_lparen_next("pattern bindings should be enclosed in a parenthesis");
while (!curr_is_rparen()) {
m_env.begin_scope();
unsigned num_bindings = m_num_bindings;
check_lparen_next("invalid pattern binding, '(' expected");
parse_match_pattern(srt);
patterns.push_back(expr_stack().back());
expr_stack().pop_back();
parse_expr();
cases.push_back(expr_stack().back());
expr_stack().pop_back();
m_num_bindings = num_bindings;
m_env.end_scope();
check_rparen_next("invalid pattern binding, ')' expected");
}
next();
m_num_expr_frames = num_frames + 1;
expr_stack().push_back(compile_patterns(t, patterns, cases));
}
void pop_match_frame(match_frame* fr) {
m_stack.deallocate(fr);
m_num_expr_frames--;
}
expr_ref compile_patterns(expr* t, expr_ref_vector const& patterns, expr_ref_vector const& cases) {
expr_ref result(m());
var_subst sub(m(), false);
TRACE("parse_expr", tout << "term\n" << expr_ref(t, m()) << "\npatterns\n" << patterns << "\ncases\n" << cases << "\n";);
check_patterns(patterns, m().get_sort(t));
for (unsigned i = patterns.size(); i > 0; ) {
--i;
expr_ref_vector subst(m());
expr_ref cond = bind_match(t, patterns[i], subst);
expr_ref new_case(m());
if (subst.empty()) {
new_case = cases[i];
}
else {
sub(cases[i], subst.size(), subst.c_ptr(), new_case);
inv_var_shifter inv(m());
inv(new_case, subst.size(), new_case);
}
if (result) {
result = m().mk_ite(cond, new_case, result);
}
else {
// pattern match binding is ignored.
result = new_case;
}
}
TRACE("parse_expr", tout << result << "\n";);
return result;
}
void check_patterns(expr_ref_vector const& patterns, sort* s) {
if (!dtutil().is_datatype(s))
throw parser_exception("pattern matching is only supported for algebraic datatypes");
ptr_vector<func_decl> const& cons = *dtutil().get_datatype_constructors(s);
for (expr * arg : patterns) if (is_var(arg)) return;
if (patterns.size() < cons.size())
throw parser_exception("non-exhaustive pattern match");
ast_fast_mark1 marked;
for (expr * arg : patterns)
marked.mark(to_app(arg)->get_decl(), true);
for (func_decl * f : cons)
if (!marked.is_marked(f))
throw parser_exception("a constructor is missing from pattern match");
}
// compute match condition and substitution
// t is shifted by size of subst.
expr_ref bind_match(expr* t, expr* pattern, expr_ref_vector& subst) {
expr_ref tsh(m());
if (is_var(pattern)) {
shifter()(t, 1, tsh);
subst.push_back(tsh);
return expr_ref(m().mk_true(), m());
}
else {
SASSERT(is_app(pattern));
func_decl * f = to_app(pattern)->get_decl();
func_decl * r = dtutil().get_constructor_recognizer(f);
ptr_vector<func_decl> const * acc = dtutil().get_constructor_accessors(f);
shifter()(t, acc->size(), tsh);
for (func_decl* a : *acc) {
subst.push_back(m().mk_app(a, tsh));
}
return expr_ref(m().mk_app(r, t), m());
}
}
/**
* parse a match pattern
* (C x1 .... xn)
* C
* _
* x
*/
bool parse_constructor_pattern(sort * srt) {
if (!curr_is_lparen()) {
return false;
}
next();
svector<symbol> vars;
expr_ref_vector args(m());
symbol C(check_identifier_next("constructor symbol expected"));
while (!curr_is_rparen()) {
symbol v(check_identifier_next("variable symbol expected"));
if (v != m_underscore && vars.contains(v)) {
throw parser_exception("unexpected repeated variable in pattern expression");
}
vars.push_back(v);
}
next();
// now have C, vars
// look up constructor C,
// create bound variables based on constructor type.
// store expression in expr_stack().
// ensure that bound variables are adjusted to vars
func_decl* f = m_ctx.find_func_decl(C, 0, nullptr, vars.size(), nullptr, srt);
if (!f) {
throw parser_exception("expecting a constructor that has been declared");
}
if (!dtutil().is_constructor(f)) {
throw parser_exception("expecting a constructor");
}
if (f->get_arity() != vars.size()) {
throw parser_exception("mismatching number of variables supplied to constructor");
}
m_num_bindings += vars.size();
for (unsigned i = 0; i < vars.size(); ++i) {
var * v = m().mk_var(i, f->get_domain(i));
args.push_back(v);
if (vars[i] != m_underscore) {
m_env.insert(vars[i], local(v, m_num_bindings));
}
}
expr_stack().push_back(m().mk_app(f, args.size(), args.c_ptr()));
return true;
}
void parse_match_pattern(sort* srt) {
if (parse_constructor_pattern(srt)) {
// done
}
else if (curr_id() == m_underscore) {
// we have a wild-card.
// store dummy variable in expr_stack()
next();
var* v = m().mk_var(0, srt);
expr_stack().push_back(v);
}
else {
symbol xC(check_identifier_next("constructor symbol or variable expected"));
// check if xC is a constructor, otherwise make it a variable
// of sort srt.
try {
func_decl* f = m_ctx.find_func_decl(xC, 0, nullptr, 0, nullptr, srt);
if (!dtutil().is_constructor(f)) {
throw parser_exception("expecting a constructor, got a previously declared function");
}
if (f->get_arity() > 0) {
throw parser_exception("constructor expects arguments, but no arguments were supplied in pattern");
}
expr_stack().push_back(m().mk_const(f));
}
catch (cmd_exception &) {
var* v = m().mk_var(0, srt);
expr_stack().push_back(v);
m_env.insert(xC, local(v, m_num_bindings++));
}
}
}
symbol parse_indexed_identifier_core() {
check_underscore_next("invalid indexed identifier, '_' expected");
check_identifier("invalid indexed identifier, symbol expected");
@ -1565,7 +1792,6 @@ namespace smt2 {
m_num_expr_frames++;
}
// return true if a new frame was created.
void push_expr_frame(expr_frame * curr) {
SASSERT(curr_is_lparen());
next();
@ -1573,11 +1799,7 @@ namespace smt2 {
if (curr_is_identifier()) {
TRACE("push_expr_frame", tout << "push_expr_frame(), curr_id(): " << curr_id() << "\n";);
if (curr_id_is_let()) {
next();
check_lparen_next("invalid let declaration, '(' expected");
void * mem = m_stack.allocate(sizeof(let_frame));
new (mem) let_frame(symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
push_let_frame();
}
else if (curr_id_is_forall()) {
push_quant_frame(true);
@ -1586,19 +1808,17 @@ namespace smt2 {
push_quant_frame(false);
}
else if (curr_id_is_bang()) {
TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";);
next();
void * mem = m_stack.allocate(sizeof(attr_expr_frame));
new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size());
m_num_expr_frames++;
push_bang_frame(curr);
}
else if (curr_id_is_as() || curr_id_is_underscore()) {
TRACE("push_expr_frame", tout << "push_expr_frame(): parse_qualified_name\n";);
parse_qualified_name();
}
else if (curr_id_is_root_obj()) {
parse_root_obj();
}
else if (curr_id_is_match()) {
push_match_frame();
}
else {
push_app_frame();
}
@ -1773,6 +1993,9 @@ namespace smt2 {
m_stack.deallocate(static_cast<let_decl_frame*>(fr));
m_num_expr_frames--;
break;
case EF_MATCH:
pop_match_frame(static_cast<match_frame*>(fr));
break;
case EF_QUANT:
pop_quant_frame(static_cast<quant_frame*>(fr));
break;
@ -2232,8 +2455,10 @@ namespace smt2 {
throw cmd_exception("invalid assert command, expression required as argument");
}
expr * f = expr_stack().back();
if (!m().is_bool(f))
if (!m().is_bool(f)) {
TRACE("smt2parser", tout << expr_ref(f, m()) << "\n";);
throw cmd_exception("invalid assert command, term is not Boolean");
}
if (f == m_last_named_expr.second) {
m_ctx.assert_expr(m_last_named_expr.first, f);
}
@ -2730,6 +2955,7 @@ namespace smt2 {
m_check_sat_assuming("check-sat-assuming"),
m_define_fun_rec("define-fun-rec"),
m_define_funs_rec("define-funs-rec"),
m_match("match"),
m_underscore("_"),
m_num_open_paren(0),
m_current_file(filename) {

View file

@ -3,7 +3,6 @@ z3_add_component(sat
ba_solver.cpp
dimacs.cpp
sat_asymm_branch.cpp
sat_ccc.cpp
sat_clause.cpp
sat_clause_set.cpp
sat_clause_use_list.cpp

View file

@ -1,604 +0,0 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
sat_ccc.cpp
Abstract:
A variant of Concurrent Cube and Conquer
Author:
Nikolaj Bjorner (nbjorner) 2017-4-17
Notes:
The cube process spawns conquer threads to search parts of the
state space.
The conquer threads have two modes:
- emulation mode - where they try to outpace the cuber on the same search tree
- complement mode - where they solve a sub-branch not yet explored by the cuber.
When the conquer thread returns a solved cube it is processed in the following ways:
- ignore if solved_id \not\in decisions
- mark d as closed if d \in decisions, such that d is marked by solved id
- backjump otherwise, conquer thread has solved a branch attempted by the cuber
--*/
#include "sat_solver.h"
#include "sat_lookahead.h"
#include "sat_ccc.h"
using namespace sat;
// ------------
// cuber
ccc::cuber::cuber(ccc& c): m_ccc(c), m_lh(alloc(lookahead, c.m_s)), m_branch_id(0) {}
lbool ccc::cuber::search() {
while (true) {
m_branch_id = 0;
m_last_closure_level = 1000;
m_lh->init_search();
m_lh->m_model.reset();
lookahead::scoped_level _sl(*m_lh.get(), m_lh->c_fixed_truth);
m_lh->m_search_mode = lookahead_mode::searching;
lbool r = research();
if (r == l_true) {
m_ccc.m_model = m_lh->get_model();
}
if (false && r == l_undef) {
continue;
}
m_lh->collect_statistics(m_ccc.m_lh_stats);
return r;
}
}
lbool ccc::cuber::research() {
m_ccc.m_s.checkpoint();
if (m_lh->inconsistent()) {
return l_false;
}
if (pop_lookahead()) {
return l_undef;
}
if (get_solved()) {
return l_false;
}
m_lh->inc_istamp();
literal l = m_lh->choose();
if (m_lh->inconsistent()) {
return l_false;
}
if (l == null_literal) {
return l_true;
}
if (!m_decisions.empty()) {
m_ccc.put_decision(m_decisions.back());
}
// update trail and m_decisions
++m_lh->m_stats.m_decisions;
unsigned parent_id = m_decisions.empty() ? 0 : m_decisions.back().m_id;
unsigned spawn_id = spawn_conquer();
unsigned branch1 = m_branch_id++;
unsigned branch2 = m_branch_id++;
decision d(branch1, m_decisions.size() + 1, l, parent_id, spawn_id);
m_decisions.push_back(d);
IF_VERBOSE(2, d.pp(verbose_stream() << "select " << m_last_closure_level << " ") << "\n";);
IF_VERBOSE(2, verbose_stream() << "select " << pp_prefix(m_lh->m_prefix, m_lh->m_trail_lim.size()) << ": " << l << " " << m_lh->m_trail.size() << "\n";);
IF_VERBOSE(3, pp(verbose_stream(), m_decisions) << "\n"; );
TRACE("sat", tout << "choose: " << l << "\n";);
m_lh->push(l, m_lh->c_fixed_truth);
lbool r = research();
if (r == l_false) {
m_lh->pop();
if (m_decisions.back().is_closed()) {
// branch was solved by a spawned conquer process
IF_VERBOSE(1, m_decisions.back().pp(verbose_stream() << "closed ") << "\n";);
r = l_false;
m_decisions.pop_back();
}
else {
if (spawn_id > 0) {
free_conquer(spawn_id);
m_last_closure_level *= 3;
m_last_closure_level /= 4;
}
m_lh->inc_istamp();
m_lh->flip_prefix();
m_lh->push(~l, m_lh->c_fixed_truth);
m_decisions.back().negate();
m_decisions.back().m_id = branch2;
m_decisions.back().m_spawn_id = 0;
r = research();
if (r == l_false) {
m_lh->pop();
m_decisions.pop_back();
}
}
}
return r;
}
bool ccc::cuber::pop_lookahead() {
return false;
scoped_ptr<lookahead> new_lh;
bool result = false;
#pragma omp critical (ccc_new_lh)
{
if (m_ccc.m_new_lh) {
new_lh = m_ccc.m_new_lh.detach();
result = true;
}
}
if (new_lh) {
m_lh->collect_statistics(m_ccc.m_lh_stats);
m_lh = new_lh.detach();
}
return result;
}
void ccc::cuber::update_closure_level(decision const& d, int offset) {
m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4;
if (m_last_closure_level >= static_cast<unsigned>(abs(offset))) {
m_last_closure_level += offset;
}
}
unsigned ccc::cuber::spawn_conquer() {
unsigned result = 0;
//
// decisions must have been solved at a higher level by a conquer thread
//
if (!m_free_threads.empty()) {
if (m_last_closure_level <= m_decisions.size()) {
result = m_free_threads.back();
++m_ccc.m_ccc_stats.m_spawn_opened;
m_free_threads.pop_back();
}
else {
IF_VERBOSE(1, verbose_stream() << m_last_closure_level << " " << m_decisions.size() << "\n";);
}
}
return result;
}
void ccc::cuber::free_conquer(unsigned id) {
if (id != 0) {
m_free_threads.push_back(id);
}
}
bool ccc::cuber::get_solved() {
// check if CDCL solver got ahead.
bool do_pop = false;
solution sol;
while (true) {
bool is_empty = true;
#pragma omp critical (ccc_solved)
{
if (do_pop) m_ccc.m_solved.pop_front();
if (!m_ccc.m_solved.empty()) {
sol = m_ccc.m_solved.top();
is_empty = false;
}
}
if (is_empty) {
return false;
}
do_pop = true;
unsigned branch_id = sol.m_branch_id;
unsigned thread_id = sol.m_thread_id;
bool found = false;
for (unsigned i = m_decisions.size(); i > 0; ) {
--i;
decision& d = m_decisions[i];
if (branch_id == d.m_id) {
if (d.m_spawn_id == thread_id && thread_id != 0) {
SASSERT(d.m_spawn_id > 0);
IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": spawn close ") << "\n";);
++m_ccc.m_ccc_stats.m_spawn_closed;
d.close();
free_conquer(thread_id);
update_closure_level(d, -1);
break;
}
else {
IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": conquer ") << "\n";);
++m_ccc.m_ccc_stats.m_cdcl_closed;
update_closure_level(d, 1);
return true;
}
}
// branch is even, d has moved to the next branch
if (branch_id == (d.m_id & ~0x1) && d.m_spawn_id == thread_id && thread_id != 0) {
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": spawn conquer ") << "\n";);
++m_ccc.m_ccc_stats.m_cdcl_closed;
update_closure_level(d, 1);
return true;
}
}
}
}
// ---------------------
// conquer state machine
lbool ccc::conquer::search() {
try {
if (s.inconsistent()) return l_false;
s.init_search();
s.propagate(false);
if (s.inconsistent()) return l_false;
s.cleanup();
s.simplify_problem();
if (s.inconsistent()) return l_false;
while (true) {
SASSERT(!s.inconsistent());
lbool r = bounded_search();
if (r != l_undef)
return r;
s.restart();
s.simplify_problem();
if (s.check_inconsistent()) return l_false;
s.gc();
push_lookahead();
}
}
catch (solver::abort_solver) {
return l_undef;
}
}
void ccc::conquer::replay_decisions() {
s.propagate(true);
for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < m_decisions.size(); ++i) {
decision const& d = m_decisions[i];
IF_VERBOSE(2, verbose_stream() << thread_id << ": replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";);
if (!push_decision(d)) {
// negation of decision is implied.
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": backjump to level " << i << " ") << "\n";);
while (m_decisions.size() > i) {
pop_decision(m_decisions.back());
m_decisions.pop_back();
}
break;
}
if (d.m_spawn_id == thread_id && d.is_left()) {
// we pushed the right branch on this thread.
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": skip left branch on level " << i + 1 << " ") << "\n";);
break;
}
}
}
void ccc::conquer::pop_decision(decision const& d) {
unsigned tid = 0;
if (d.is_spawned(thread_id)) {
tid = thread_id;
m_spawned = false;
IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": retire spawn ") << "\n";);
}
#pragma omp critical (ccc_solved)
{
m_ccc.m_solved.push(solution(tid, d.m_id));
}
}
void ccc::conquer::push_lookahead() {
return;
#pragma omp critical (ccc_new_lh)
{
if (!m_ccc.m_new_lh && m_ccc.m_num_clauses > s.num_clauses()) {
std::cout << "push " << s.num_clauses() << "\n";
m_ccc.m_new_lh = alloc(lookahead, s);
m_ccc.m_num_clauses = s.num_clauses();
}
}
}
bool ccc::conquer::push_decision(decision const& d) {
literal lit = d.get_literal(thread_id);
switch (s.value(lit)) {
case l_false:
//TBD:
s.m_restart_threshold = s.m_config.m_restart_initial;
//s.m_conflicts_since_last_restart = 0;
return false;
case l_true:
s.push();
break;
case l_undef:
s.push();
s.assign(lit, justification());
s.propagate(true);
break;
}
m_spawned |= d.is_spawned(thread_id);
return true;
}
bool ccc::conquer::cube_decision() {
decision d;
bool use_cube_decision = false;
SASSERT(s.m_qhead == s.m_trail.size());
while (true) {
if (!m_ccc.get_decision(thread_id, d)) {
return false;
}
if (d.is_spawned(thread_id)) IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << " ") << "\n";);
if (!m_decisions.empty() && m_decisions.back().m_depth + 1 < d.m_depth) {
if (d.is_spawned(thread_id)) {
pop_decision(d);
}
}
else {
break;
}
}
SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 >= d.m_depth);
if (!m_decisions.empty() && m_decisions.back().is_spawned(thread_id) && m_decisions.back().m_depth == d.m_depth) {
SASSERT(d.m_spawn_id == 0);
SASSERT(m_decisions.back().is_left());
SASSERT(!d.is_left());
IF_VERBOSE(1, verbose_stream() << thread_id << " inherit spawn\n";);
m_decisions.back().m_spawn_id = 0;
m_spawned = false;
}
SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 >= d.m_depth);
while (!m_decisions.empty() && m_decisions.back().m_depth >= d.m_depth) {
// check_non_model("cube decision", m_decisions);
if (m_decisions.back().is_spawned(thread_id)) {
pop_decision(m_decisions.back());
}
m_decisions.pop_back();
}
SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 == d.m_depth);
SASSERT(m_decisions.empty() || m_decisions.back().m_id == d.m_parent);
if (m_spawned) {
m_decisions.push_back(d);
return true;
}
s.pop_reinit(s.scope_lvl() - m_decisions.size());
SASSERT(s.m_qhead == s.m_trail.size());
SASSERT(s.scope_lvl() == m_decisions.size());
literal lit = d.get_literal(thread_id);
IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": cube ") << "\n";);
IF_VERBOSE(3, pp(verbose_stream() << thread_id << ": push ", m_decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n";
if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";);
if (push_decision(d)) {
m_decisions.push_back(d);
}
else {
pop_decision(d);
}
return true;
}
lbool ccc::conquer::bounded_search() {
while (true) {
s.checkpoint();
bool done = false;
while (!done) {
replay_decisions();
lbool is_sat = s.propagate_and_backjump_step(done);
if (is_sat != l_true) return is_sat;
}
s.gc();
if (!cube_decision() && !s.decide()) {
lbool is_sat = s.final_check();
if (is_sat != l_undef) {
return is_sat;
}
}
}
}
// --------------
// shared state
std::ostream& ccc::decision::pp(std::ostream& out) const {
out << "("
<< "id:" << m_id
<< " l:" << m_literal
<< " d:" << m_depth;
if (m_spawn_id != 0) {
out << " s:" << m_spawn_id;
}
out << ") ";
return out;
}
std::ostream& ccc::pp(std::ostream& out, svector<decision> const& v) {
for (unsigned i = 0; i < v.size(); ++i) {
v[i].pp(out);
}
return out;
}
bool ccc::get_decision(unsigned thread_id, decision& d) {
SASSERT(0 < thread_id && thread_id <= m_decisions.size());
bool result = false;
#pragma omp critical (ccc_decisions)
{
if (!m_decisions[thread_id - 1].empty()) {
d = m_decisions[thread_id - 1].pop_front();
result = true;
}
}
return result;
}
void ccc::put_decision(decision const& d) {
for (unsigned i = 0; i < m_num_conquer; ++i) {
#pragma omp critical (ccc_decisions)
{
while (false && !m_decisions[i].empty()) { // introduces contention.
decision d = m_decisions[i].back();
if (d.m_depth < d.m_depth || d.m_spawn_id != 0) {
break;
}
m_decisions[i].pop_back();
}
m_decisions[i].push(d);
}
}
}
lbool ccc::search() {
enum par_exception_kind {
DEFAULT_EX,
ERROR_EX
};
// set_model();
m_cancel = false;
scoped_limits scoped_rlimit(m_s.rlimit());
ptr_vector<conquer> solvers;
int finished_id = -1;
std::string ex_msg;
par_exception_kind ex_kind;
unsigned error_code = 0;
lbool result = l_undef;
m_decisions.reset();
cuber cuber(*this);
m_num_conquer = m_s.m_config.m_num_threads;
int num_threads = 1 + m_num_conquer; // for ccc-infinity only two threads.
for (int i = 1; i < num_threads; ++i) {
m_s.m_params.set_uint("random_seed", m_s.m_rand());
conquer* s1 = alloc(conquer, *this, m_s.m_params, i);
solvers.push_back(s1);
s1->s.copy(m_s);
scoped_rlimit.push_child(&(s1->m_limit));
m_decisions.push_back(queue<decision>());
}
for (unsigned i = 1; i < m_num_conquer; ++i) {
cuber.m_free_threads.push_back(i);
}
#pragma omp parallel for
for (int i = 0; i < num_threads; ++i) {
try {
lbool r = l_undef;
if (i == 0) {
r = cuber.search();
}
else {
r = solvers[i-1]->search();
}
bool first = false;
#pragma omp critical (par_solver)
{
if (finished_id == -1) {
finished_id = i;
first = true;
result = r;
}
}
if (first) {
for (unsigned j = 0; j < solvers.size(); ++j) {
solvers[j]->m_limit.cancel();
}
// cancel lookahead solver:
m_cancel = true;
}
}
catch (z3_error & err) {
error_code = err.error_code();
ex_kind = ERROR_EX;
}
catch (z3_exception & ex) {
ex_msg = ex.msg();
ex_kind = DEFAULT_EX;
}
}
if (finished_id > 0 && result == l_true) {
// set model from auxiliary solver
m_model = solvers[finished_id - 1]->s.get_model();
}
for (unsigned i = 0; i < solvers.size(); ++i) {
solvers[i]->s.collect_statistics(m_lh_stats);
dealloc(solvers[i]);
}
if (finished_id == -1) {
switch (ex_kind) {
case ERROR_EX: throw z3_error(error_code);
default: throw default_exception(ex_msg.c_str());
}
}
#if 0
if (result == l_true) {
for (unsigned i = 1; i < m_model.size(); ++i) {
std::cout << "push_model(" << i << ", " << (m_model[i] > 0 ? "false" : "true") << ");\n";
}
}
#endif
return result;
}
#if 0
void ccc::push_model(unsigned v, bool sign) {
if (m_values.size() <= v) {
m_values.resize(v + 1);
}
m_values[v] = sign;
}
void ccc::check_non_model(char const* fn, svector<decision> const& decisions) {
for (unsigned i = 0; i < decisions.size(); ++i) {
decision d = decisions[i];
literal lit = d.m_literal;
if (m_values[lit.var()] != lit.sign()) return;
}
IF_VERBOSE(1, pp(verbose_stream() << "backtracking from model " << fn << " ", decisions) << "\n";);
}
#endif

View file

@ -1,150 +0,0 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
sat_ccc.h
Abstract:
A variant of Concurrent Cube and Conquer
Author:
Nikolaj Bjorner (nbjorner) 2017-4-17
Notes:
--*/
#ifndef _SAT_CCC_H_
#define _SAT_CCC_H_
#include "util/queue.h"
namespace sat {
class ccc {
struct decision {
unsigned m_id; // unique identifier for decision
unsigned m_depth; // depth of decision
literal m_literal; // decision literal
unsigned m_parent; // id of parent
int m_spawn_id; // thread id of conquer thread processing complented branch.
// = 0 if not spawned.
// > 0 if active spawn is in progress
// < 0 if thread has closed the branch
decision(unsigned id, unsigned d, literal last, unsigned parent_id, unsigned spawn):
m_id(id), m_depth(d), m_literal(last), m_parent(parent_id), m_spawn_id(spawn) {}
decision():
m_id(0), m_depth(0), m_literal(null_literal), m_parent(0), m_spawn_id(0) {}
void close() { SASSERT(m_spawn_id > 0); m_spawn_id = -m_spawn_id; }
bool is_closed() const { return m_spawn_id < 0; }
void negate() { m_literal.neg(); }
bool is_left() const { return 0 == (m_id & 0x1); }
bool is_spawned(unsigned thread_id) const { return m_spawn_id == thread_id; }
// the left branch has an even branch_id.
// the branch is spawned if it is even and the spawn_id is the same as the thread_id, and furthermore it is exploring the left branch.
// it may explore the right branch, but is then not in a spawned mode.
// we retain the spawn id so that the spawned thread can be re-spun.
literal get_literal(unsigned thread_id) const { return ((m_id & 0x1) == 0 && thread_id == m_spawn_id) ? ~m_literal : m_literal; }
std::ostream& pp(std::ostream& out) const;
};
struct solution {
unsigned m_thread_id;
unsigned m_branch_id;
solution(unsigned t, unsigned s): m_thread_id(t), m_branch_id(s) {}
solution(): m_thread_id(0), m_branch_id(0) {}
};
struct stats {
unsigned m_spawn_closed;
unsigned m_spawn_opened;
unsigned m_cdcl_closed;
stats() { reset(); }
void reset() {
memset(this, 0, sizeof(*this));
}
};
struct conquer {
reslimit m_limit;
ccc& m_ccc;
solver s;
svector<decision> m_decisions;
unsigned thread_id;
bool m_spawned;
conquer(ccc& super, params_ref const& p, unsigned tid): m_ccc(super), s(p, m_limit), thread_id(tid), m_spawned(false) {}
lbool search();
bool cube_decision();
lbool bounded_search();
bool push_decision(decision const& d);
void pop_decision(decision const& d);
void push_lookahead();
void replay_decisions();
};
struct cuber {
ccc& m_ccc;
scoped_ptr<lookahead> m_lh;
unsigned m_branch_id;
unsigned m_last_closure_level;
unsigned_vector m_free_threads;
svector<decision> m_decisions;
cuber(ccc& c);
lbool search();
lbool research();
bool get_solved();
void update_closure_level(decision const& d, int offset);
unsigned spawn_conquer();
void free_conquer(unsigned thread_id);
bool pop_lookahead();
};
solver& m_s;
queue<solution> m_solved;
vector<queue<decision> > m_decisions;
scoped_ptr<lookahead> m_new_lh;
unsigned m_num_clauses;
unsigned m_num_conquer;
model m_model;
volatile bool m_cancel;
::statistics m_lh_stats;
stats m_ccc_stats;
void put_decision(decision const& d);
bool get_decision(unsigned thread_id, decision& d);
static std::ostream& pp(std::ostream& out, svector<decision> const& v);
void push_model(unsigned v, bool sign);
void set_model();
bool trail_in_model(literal_vector const& trail) const;
void check_non_model(char const* fn, svector<decision> const& decisions);
public:
ccc(solver& s): m_s(s), m_num_clauses(s.num_clauses()) {}
lbool search();
model const& get_model() const { return m_model; }
void collect_statistics(::statistics& st) {
st.copy(m_lh_stats);
st.update("ccc-spawn-closed", m_ccc_stats.m_spawn_closed);
st.update("ccc-cdcl-closed", m_ccc_stats.m_cdcl_closed);
st.update("ccc-spawn-opened", m_ccc_stats.m_spawn_opened);
}
};
}
#endif

View file

@ -39,7 +39,6 @@ namespace sat {
m_local_search = 0;
m_lookahead_search = false;
m_lookahead_simplify = false;
m_ccc = false;
updt_params(p);
}
@ -86,9 +85,11 @@ namespace sat {
m_local_search = p.local_search();
m_local_search_threads = p.local_search_threads();
m_lookahead_simplify = p.lookahead_simplify();
m_lookahead_cube = p.lookahead_cube();
m_lookahead_search = p.lookahead_search();
m_lookahead_reward = p.lookahead_reward();
m_ccc = p.ccc();
m_lookahead_cube_fraction = p.lookahead_cube_fraction();
m_lookahead_cube_cutoff = p.lookahead_cube_cutoff();
// These parameters are not exposed
m_simplify_mult1 = _p.get_uint("simplify_mult1", 300);
@ -166,6 +167,7 @@ namespace sat {
else {
throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting");
}
m_dimacs_display = p.dimacs_display();
}
void config::collect_param_descrs(param_descrs & r) {

View file

@ -75,8 +75,10 @@ namespace sat {
bool m_local_search;
bool m_lookahead_search;
bool m_lookahead_simplify;
bool m_lookahead_cube;
unsigned m_lookahead_cube_cutoff;
double m_lookahead_cube_fraction;
symbol m_lookahead_reward;
bool m_ccc;
unsigned m_simplify_mult1;
double m_simplify_mult2;
@ -96,6 +98,8 @@ namespace sat {
symbol m_drat_file;
bool m_drat_check;
bool m_dimacs_display;
symbol m_always_true;
symbol m_always_false;
symbol m_caching;

View file

@ -1710,6 +1710,47 @@ namespace sat {
return true;
}
void lookahead::cube() {
m_model.reset();
scoped_level _sl(*this, c_fixed_truth);
literal_vector trail;
m_search_mode = lookahead_mode::searching;
double freevars_threshold = 0;
while (true) {
TRACE("sat", display(tout););
inc_istamp();
checkpoint();
literal l = choose();
if (inconsistent()) {
freevars_threshold = m_freevars.size();
if (!backtrack(trail)) return;
continue;
}
unsigned depth = m_trail_lim.size();
if (l == null_literal ||
(m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) ||
(m_config.m_cube_cutoff == 0 && m_freevars.size() < freevars_threshold)) {
display_cube(std::cout);
set_conflict();
if (!backtrack(trail)) return;
freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth));
continue;
}
TRACE("sat", tout << "choose: " << l << " " << trail << "\n";);
++m_stats.m_decisions;
IF_VERBOSE(1, printf("\r");
std::stringstream strm;
strm << pp_prefix(m_prefix, m_trail_lim.size());
for (unsigned i = 0; i < 50; ++i) strm << " ";
printf(strm.str().c_str());
fflush(stdout);
);
push(l, c_fixed_truth);
trail.push_back(l);
SASSERT(inconsistent() || !is_unsat());
}
}
lbool lookahead::search() {
m_model.reset();
scoped_level _sl(*this, c_fixed_truth);
@ -1719,10 +1760,6 @@ namespace sat {
TRACE("sat", display(tout););
inc_istamp();
checkpoint();
if (inconsistent()) {
if (!backtrack(trail)) return l_false;
continue;
}
literal l = choose();
if (inconsistent()) {
if (!backtrack(trail)) return l_false;
@ -1764,6 +1801,14 @@ namespace sat {
}
}
std::ostream& lookahead::display_cube(std::ostream& out) const {
out << "c";
for (literal l : m_assumptions) {
out << " " << ~l;
}
return out << "\n";
}
std::ostream& lookahead::display_binary(std::ostream& out) const {
for (unsigned i = 0; i < m_binary.size(); ++i) {
literal_vector const& lits = m_binary[i];
@ -1818,7 +1863,7 @@ namespace sat {
literal lookahead::choose() {
literal l = null_literal;
while (l == null_literal) {
while (l == null_literal && !inconsistent()) {
pre_select();
if (m_lookahead.empty()) {
break;
@ -2013,6 +2058,8 @@ namespace sat {
else {
warning_msg("Reward type not recognized");
}
m_config.m_cube_cutoff = m_s.m_config.m_lookahead_cube_cutoff;
m_config.m_cube_fraction = m_s.m_config.m_lookahead_cube_fraction;
}
void lookahead::collect_statistics(statistics& st) const {

View file

@ -84,6 +84,8 @@ namespace sat {
unsigned m_dl_max_iterations;
unsigned m_tc1_limit;
reward_t m_reward_type;
unsigned m_cube_cutoff;
double m_cube_fraction;
config() {
m_max_hlevel = 50;
@ -95,6 +97,8 @@ namespace sat {
m_dl_max_iterations = 32;
m_tc1_limit = 10000000;
m_reward_type = ternary_reward;
m_cube_cutoff = 0;
m_cube_fraction = 0.4;
}
};
@ -446,6 +450,8 @@ namespace sat {
std::ostream& display_clauses(std::ostream& out) const;
std::ostream& display_values(std::ostream& out) const;
std::ostream& display_lookahead(std::ostream& out) const;
std::ostream& display_cube(std::ostream& out) const;
void init_search();
void checkpoint();
@ -474,6 +480,14 @@ namespace sat {
return search();
}
/**
\brief create cubes to std-out in DIMACS form.
The cubes are controlled using cut-depth and cut-fraction parameters.
If cut-depth != 0, then it is used to control the depth of cuts.
Otherwise, cut-fraction gives an adaptive threshold for creating cuts.
*/
void cube();
literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars);
/**
\brief simplify set of clauses by extracting units from a lookahead at base level.

View file

@ -34,8 +34,11 @@ def_module_params('sat',
('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'),
('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'),
('local_search', BOOL, False, 'use local search instead of CDCL'),
('lookahead_cube', BOOL, False, 'use lookahead solver to create cubes'),
('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'),
('lookahead.cube.cutoff', UINT, 0, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'),
('lookahead_search', BOOL, False, 'use lookahead solver'),
('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'),
('lookahead.reward', SYMBOL, 'heuleu', 'select lookahead heuristic: ternary, hs (Heule Schur), heuleu (Heule Unit), or unit'),
('ccc', BOOL, False, 'use Concurrent Cube and Conquer solver')
))
('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving')))

View file

@ -20,7 +20,6 @@ Revision History:
#include "sat/sat_solver.h"
#include "sat/sat_integrity_checker.h"
#include "sat/sat_lookahead.h"
#include "sat/sat_ccc.h"
#include "util/luby.h"
#include "util/trace.h"
#include "util/max_cliques.h"
@ -847,16 +846,25 @@ namespace sat {
pop_to_base_level();
IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";);
SASSERT(at_base_lvl());
if (m_config.m_dimacs_display) {
display_dimacs(std::cout);
for (unsigned i = 0; i < num_lits; ++lits) {
std::cout << dimacs_lit(lits[i]) << " 0\n";
}
return l_undef;
}
if (m_config.m_lookahead_search && num_lits == 0) {
return lookahead_search();
}
if (m_config.m_lookahead_cube && num_lits == 0) {
lookahead_cube();
return l_undef;
}
if (m_config.m_local_search) {
return do_local_search(num_lits, lits);
}
if (m_config.m_ccc && num_lits == 0) {
return do_ccc();
}
if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0) && !m_par) {
SASSERT(scope_lvl() == 0);
return check_par(num_lits, lits);
}
flet<bool> _searching(m_searching, true);
@ -913,13 +921,6 @@ namespace sat {
if (check_inconsistent()) return l_false;
gc();
#if 0
if (m_clauses.size() < 65000) {
return do_ccc();
return lookahead_search();
}
#endif
if (m_config.m_restart_max <= m_restarts) {
m_reason_unknown = "sat.max.restarts";
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";);
@ -951,12 +952,16 @@ namespace sat {
return r;
}
lbool solver::do_ccc() {
ccc c(*this);
lbool r = c.search();
m_model = c.get_model();
c.collect_statistics(m_aux_stats);
return r;
void solver::lookahead_cube() {
lookahead lh(*this);
try {
lh.cube();
}
catch (z3_exception&) {
lh.collect_statistics(m_aux_stats);
throw;
}
lh.collect_statistics(m_aux_stats);
}
lbool solver::lookahead_search() {
@ -1497,10 +1502,7 @@ namespace sat {
}
void solver::sort_watch_lits() {
vector<watch_list>::iterator it = m_watches.begin();
vector<watch_list>::iterator end = m_watches.end();
for (; it != end; ++it) {
watch_list & wlist = *it;
for (watch_list & wlist : m_watches) {
std::stable_sort(wlist.begin(), wlist.end(), watched_lt());
}
}

View file

@ -403,6 +403,7 @@ namespace sat {
void exchange_par();
lbool check_par(unsigned num_lits, literal const* lits);
lbool lookahead_search();
void lookahead_cube();
lbool do_local_search(unsigned num_lits, literal const* lits);
lbool do_ccc();

View file

@ -149,7 +149,6 @@ public:
virtual void set_progress_callback(progress_callback * callback) {}
void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) {
if (weights != 0) {
for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]);
@ -212,6 +211,11 @@ public:
init_reason_unknown();
r = m_solver.check(m_asms.size(), m_asms.c_ptr());
if (r == l_undef && m_solver.get_config().m_dimacs_display) {
for (auto const& kv : m_map) {
std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, m) << "\n";
}
}
switch (r) {
case l_true:
@ -806,14 +810,12 @@ private:
}
sat::model const & ll_m = m_solver.get_model();
model_ref md = alloc(model, m);
atom2bool_var::iterator it = m_map.begin();
atom2bool_var::iterator end = m_map.end();
for (; it != end; ++it) {
expr * n = it->m_key;
for (auto const& kv : m_map) {
expr * n = kv.m_key;
if (is_app(n) && to_app(n)->get_num_args() > 0) {
continue;
}
sat::bool_var v = it->m_value;
sat::bool_var v = kv.m_value;
switch (sat::value_at(v, ll_m)) {
case l_true:
md->register_decl(to_app(n)->get_decl(), m.mk_true());

View file

@ -16,11 +16,11 @@ Author:
Notes:
--*/
#include "ast/ast_pp.h"
#include "tactic/tactical.h"
#include "tactic/filter_model_converter.h"
#include "sat/tactic/goal2sat.h"
#include "sat/sat_solver.h"
#include "tactic/filter_model_converter.h"
#include "ast/ast_smt2_pp.h"
#include "model/model_v2_pp.h"
class sat_tactic : public tactic {
@ -56,11 +56,9 @@ class sat_tactic : public tactic {
sat::literal_vector assumptions;
m_goal2sat(*g, m_params, m_solver, map, dep2asm);
TRACE("sat_solver_unknown", tout << "interpreted_atoms: " << map.interpreted_atoms() << "\n";
atom2bool_var::iterator it = map.begin();
atom2bool_var::iterator end = map.end();
for (; it != end; ++it) {
if (!is_uninterp_const(it->m_key))
tout << mk_ismt2_pp(it->m_key, m) << "\n";
for (auto const& kv : map) {
if (!is_uninterp_const(kv.m_key))
tout << mk_ismt2_pp(kv.m_key, m) << "\n";
});
g->reset();
g->m().compact_memory();
@ -70,6 +68,11 @@ class sat_tactic : public tactic {
TRACE("sat_dimacs", m_solver.display_dimacs(tout););
dep2assumptions(dep2asm, assumptions);
lbool r = m_solver.check(assumptions.size(), assumptions.c_ptr());
if (r == l_undef && m_solver.get_config().m_dimacs_display) {
for (auto const& kv : map) {
std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, g->m()) << "\n";
}
}
if (r == l_false) {
expr_dependency * lcore = 0;
if (produce_core) {
@ -90,11 +93,9 @@ class sat_tactic : public tactic {
model_ref md = alloc(model, m);
sat::model const & ll_m = m_solver.get_model();
TRACE("sat_tactic", for (unsigned i = 0; i < ll_m.size(); i++) tout << i << ":" << ll_m[i] << " "; tout << "\n";);
atom2bool_var::iterator it = map.begin();
atom2bool_var::iterator end = map.end();
for (; it != end; ++it) {
expr * n = it->m_key;
sat::bool_var v = it->m_value;
for (auto const& kv : map) {
expr * n = kv.m_key;
sat::bool_var v = kv.m_value;
TRACE("sat_tactic", tout << "extracting value of " << mk_ismt2_pp(n, m) << "\nvar: " << v << "\n";);
switch (sat::value_at(v, ll_m)) {
case l_true:
@ -126,17 +127,15 @@ class sat_tactic : public tactic {
void dep2assumptions(obj_map<expr, sat::literal>& dep2asm,
sat::literal_vector& assumptions) {
obj_map<expr, sat::literal>::iterator it = dep2asm.begin(), end = dep2asm.end();
for (; it != end; ++it) {
assumptions.push_back(it->m_value);
for (auto const& kv : dep2asm) {
assumptions.push_back(kv.m_value);
}
}
void mk_asm2dep(obj_map<expr, sat::literal>& dep2asm,
u_map<expr*>& lit2asm) {
obj_map<expr, sat::literal>::iterator it = dep2asm.begin(), end = dep2asm.end();
for (; it != end; ++it) {
lit2asm.insert(it->m_value.index(), it->m_key);
for (auto const& kv : dep2asm) {
lit2asm.insert(kv.m_value.index(), kv.m_key);
}
}
};

View file

@ -81,10 +81,11 @@ void run_solver(lp_params & params, char const * mps_file_name) {
solver->settings().report_frequency = params.rep_freq();
solver->settings().print_statistics = params.print_stats();
solver->settings().simplex_strategy() = lp:: simplex_strategy_enum::lu;
solver->find_maximal_solution();
*(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl;
if (solver->get_status() == lp::lp_status::OPTIMAL) {
if (solver->get_status() == lp::OPTIMAL) {
if (params.min()) {
solver->flip_costs();
}

View file

@ -1753,10 +1753,6 @@ namespace smt {
m_use_filters(use_filters) {
}
context & get_context() {
return m_context;
}
/**
\brief Create a new code tree for the given quantifier.
@ -2020,26 +2016,20 @@ namespace smt {
void execute(code_tree * t) {
TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout););
init(t);
enode_vector::const_iterator it = t->get_candidates().begin();
enode_vector::const_iterator end = t->get_candidates().end();
if (t->filter_candidates()) {
for (; it != end; ++it) {
enode * app = *it;
for (enode * app : t->get_candidates()) {
if (!app->is_marked() && app->is_cgr()) {
execute_core(t, app);
app->set_mark();
}
}
it = t->get_candidates().begin();
for (; it != end; ++it) {
enode * app = *it;
for (enode * app : t->get_candidates()) {
if (app->is_marked())
app->unset_mark();
}
}
else {
for (; it != end; ++it) {
enode * app = *it;
for (enode * app : t->get_candidates()) {
TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";);
if (app->is_cgr()) {
TRACE("trigger_bug", tout << "is_cgr\n";);
@ -2825,15 +2815,13 @@ namespace smt {
} // end of execute_core
void display_trees(std::ostream & out, const ptr_vector<code_tree> & trees) {
ptr_vector<code_tree>::const_iterator it = trees.begin();
ptr_vector<code_tree>::const_iterator end = trees.end();
unsigned lbl = 0;
for (; it != end; ++it, ++lbl) {
code_tree * tree = *it;
for (code_tree* tree : trees) {
if (tree) {
out << "tree for f" << lbl << "\n";
out << *tree;
}
++lbl;
}
}

View file

@ -38,7 +38,7 @@ expr * datatype_factory::get_some_value(sort * s) {
}
expr * r = m_manager.mk_app(c, args.size(), args.c_ptr());
register_value(r);
TRACE("datatype_factory", tout << mk_pp(r, m_util.get_manager()) << "\n";);
TRACE("datatype", tout << mk_pp(r, m_util.get_manager()) << "\n";);
return r;
}
@ -48,7 +48,7 @@ expr * datatype_factory::get_some_value(sort * s) {
expr * datatype_factory::get_last_fresh_value(sort * s) {
expr * val = 0;
if (m_last_fresh_value.find(s, val)) {
TRACE("datatype_factory", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";);
TRACE("datatype", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";);
return val;
}
value_set * set = get_value_set(s);
@ -68,7 +68,7 @@ bool datatype_factory::is_subterm_of_last_value(app* e) {
}
contains_app contains(m_manager, e);
bool result = contains(last);
TRACE("datatype_factory", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";);
TRACE("datatype", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";);
return result;
}
@ -126,7 +126,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) {
m_last_fresh_value.insert(s, new_value);
}
}
TRACE("datatype_factory", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";);
TRACE("datatype", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";);
return new_value;
}
}
@ -136,7 +136,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) {
expr * datatype_factory::get_fresh_value(sort * s) {
TRACE("datatype_factory", tout << "generating fresh value for: " << s->get_name() << "\n";);
TRACE("datatype", tout << "generating fresh value for: " << s->get_name() << "\n";);
value_set * set = get_value_set(s);
// Approach 0)
// if no value for s was generated so far, then used get_some_value
@ -144,7 +144,7 @@ expr * datatype_factory::get_fresh_value(sort * s) {
expr * val = get_some_value(s);
if (m_util.is_recursive(s))
m_last_fresh_value.insert(s, val);
TRACE("datatype_factory", tout << "0. result: " << mk_pp(val, m_manager) << "\n";);
TRACE("datatype", tout << "0. result: " << mk_pp(val, m_manager) << "\n";);
return val;
}
// Approach 1)
@ -171,13 +171,13 @@ expr * datatype_factory::get_fresh_value(sort * s) {
}
expr_ref new_value(m_manager);
new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
CTRACE("datatype_factory", found_fresh_arg && set->contains(new_value), tout << mk_pp(new_value, m_manager) << "\n";);
CTRACE("datatype", found_fresh_arg && set->contains(new_value), tout << mk_pp(new_value, m_manager) << "\n";);
SASSERT(!found_fresh_arg || !set->contains(new_value));
if (!set->contains(new_value)) {
register_value(new_value);
if (m_util.is_recursive(s))
m_last_fresh_value.insert(s, new_value);
TRACE("datatype_factory", tout << "1. result: " << mk_pp(new_value, m_manager) << "\n";);
TRACE("datatype", tout << "1. result: " << mk_pp(new_value, m_manager) << "\n";);
return new_value;
}
}
@ -188,16 +188,16 @@ expr * datatype_factory::get_fresh_value(sort * s) {
if (m_util.is_recursive(s)) {
while(true) {
++num_iterations;
TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
TRACE("datatype", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(s);
for (func_decl * constructor : constructors) {
expr_ref_vector args(m_manager);
bool found_sibling = false;
unsigned num = constructor->get_arity();
TRACE("datatype_factory", tout << "checking constructor: " << constructor->get_name() << "\n";);
TRACE("datatype", tout << "checking constructor: " << constructor->get_name() << "\n";);
for (unsigned i = 0; i < num; i++) {
sort * s_arg = constructor->get_domain(i);
TRACE("datatype_factory", tout << mk_pp(s, m_manager) << " "
TRACE("datatype", tout << mk_pp(s, m_manager) << " "
<< mk_pp(s_arg, m_manager) << " are_siblings "
<< m_util.are_siblings(s, s_arg) << " is_datatype "
<< m_util.is_datatype(s_arg) << " found_sibling "
@ -212,7 +212,7 @@ expr * datatype_factory::get_fresh_value(sort * s) {
maybe_new_arg = get_fresh_value(s_arg);
}
if (!maybe_new_arg) {
TRACE("datatype_factory",
TRACE("datatype",
tout << "no argument found for " << mk_pp(s_arg, m_manager) << "\n";);
maybe_new_arg = m_model.get_some_value(s_arg);
found_sibling = false;
@ -229,11 +229,11 @@ expr * datatype_factory::get_fresh_value(sort * s) {
if (found_sibling) {
expr_ref new_value(m_manager);
new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
TRACE("datatype_factory", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";);
TRACE("datatype", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";);
m_last_fresh_value.insert(s, new_value);
if (!set->contains(new_value)) {
register_value(new_value);
TRACE("datatype_factory", tout << "2. result: " << mk_pp(new_value, m_manager) << "\n";);
TRACE("datatype", tout << "2. result: " << mk_pp(new_value, m_manager) << "\n";);
return new_value;
}
}

View file

@ -148,11 +148,8 @@ namespace smt {
}
void qi_queue::instantiate() {
svector<entry>::iterator it = m_new_entries.begin();
svector<entry>::iterator end = m_new_entries.end();
unsigned since_last_check = 0;
for (; it != end; ++it) {
entry & curr = *it;
for (entry & curr : m_new_entries) {
fingerprint * f = curr.m_qb;
quantifier * qa = static_cast<quantifier*>(f->get_data());

View file

@ -4387,9 +4387,17 @@ namespace smt {
expr* fn = to_app(q->get_pattern(0))->get_arg(0);
expr* body = to_app(q->get_pattern(1))->get_arg(0);
SASSERT(is_app(fn));
// reverse argument order so that variable 0 starts at the beginning.
expr_ref_vector subst(m);
for (expr* arg : *to_app(fn)) {
subst.push_back(arg);
}
expr_ref bodyr(m);
var_subst sub(m, false);
sub(body, subst.size(), subst.c_ptr(), bodyr);
func_decl* f = to_app(fn)->get_decl();
func_interp* fi = alloc(func_interp, m, f->get_arity());
fi->set_else(body);
fi->set_else(bodyr);
m_model->register_decl(f, fi);
}
}

View file

@ -198,19 +198,19 @@ namespace smt {
if (get_depth(n) > DEEP_EXPR_THRESHOLD) {
// if the expression is deep, then execute topological sort to avoid
// stack overflow.
// a caveat is that theory internalizers do rely on recursive descent so
// internalization over these follows top-down
TRACE("deep_internalize", tout << "expression is deep: #" << n->get_id() << "\n" << mk_ll_pp(n, m_manager););
svector<expr_bool_pair> sorted_exprs;
top_sort_expr(n, sorted_exprs);
TRACE("deep_internalize",
svector<expr_bool_pair>::const_iterator it = sorted_exprs.begin();
svector<expr_bool_pair>::const_iterator end = sorted_exprs.end();
for (; it != end; ++it) {
tout << "#" << it->first->get_id() << " " << it->second << "\n";
});
svector<expr_bool_pair>::const_iterator it = sorted_exprs.begin();
svector<expr_bool_pair>::const_iterator end = sorted_exprs.end();
for (; it != end; ++it)
internalize(it->first, it->second);
TRACE("deep_internalize", for (auto & kv : sorted_exprs) tout << "#" << kv.first->get_id() << " " << kv.second << "\n"; );
for (auto & kv : sorted_exprs) {
expr* e = kv.first;
if (!is_app(e) ||
to_app(e)->get_family_id() == null_family_id ||
to_app(e)->get_family_id() == m_manager.get_basic_family_id())
internalize(e, kv.second);
}
}
SASSERT(m_manager.is_bool(n));
if (is_gate(m_manager, n)) {

View file

@ -125,6 +125,8 @@ namespace smt {
setup_QF_FPBV();
else if (m_logic == "QF_S")
setup_QF_S();
else if (m_logic == "QF_DT")
setup_QF_DT();
else
setup_unknown();
}
@ -190,6 +192,8 @@ namespace smt {
setup_AUFLIRA();
else if (m_logic == "UFNIA")
setup_UFNIA();
else if (m_logic == "QF_DT")
setup_QF_DT();
else if (m_logic == "LRA")
setup_LRA();
else
@ -210,6 +214,10 @@ namespace smt {
m_params.m_random_initial_activity = IA_RANDOM;
}
void setup::setup_QF_DT() {
setup_QF_UF();
}
void setup::setup_QF_BVRE() {
setup_QF_BV();
setup_QF_LIA();

View file

@ -54,6 +54,7 @@ namespace smt {
// setup_<logic>(static_features & st) can only be used if the logical context will perform a single
// check.
//
void setup_QF_DT();
void setup_QF_UF();
void setup_QF_UF(static_features const & st);
void setup_QF_RDL();

View file

@ -109,8 +109,10 @@ namespace smt {
}
virtual void assert_expr(expr * t, expr * a) {
if (m_name2assertion.contains(a)) {
throw default_exception("named assertion defined twice");
}
solver_na2as::assert_expr(t, a);
SASSERT(!m_name2assertion.contains(a));
get_manager().inc_ref(t);
m_name2assertion.insert(a, t);
}

View file

@ -151,14 +151,15 @@ namespace smt {
m_autil.is_numeral(rhs, _k);
numeral offset(_k);
app * s, * t;
if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(1), s)) {
t = to_app(to_app(lhs)->get_arg(0));
expr *arg1, *arg2;
if (m_autil.is_add(lhs, arg1, arg2) && is_times_minus_one(arg2, s)) {
t = to_app(arg1);
}
else if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(0), s)) {
t = to_app(to_app(lhs)->get_arg(1));
else if (m_autil.is_add(lhs, arg1, arg2) && is_times_minus_one(arg1, s)) {
t = to_app(arg2);
}
else if (m_autil.is_mul(lhs) && to_app(lhs)->get_num_args() == 2 && m_autil.is_minus_one(to_app(lhs)->get_arg(0))) {
s = to_app(to_app(lhs)->get_arg(1));
else if (m_autil.is_mul(lhs, arg1, arg2) && m_autil.is_minus_one(arg1)) {
s = to_app(arg2);
t = mk_zero_for(s);
}
else if (!m_autil.is_arith_expr(lhs)) {
@ -170,6 +171,7 @@ namespace smt {
found_non_diff_logic_expr(n);
return false;
}
TRACE("arith", tout << expr_ref(lhs, get_manager()) << " " << expr_ref(s, get_manager()) << " " << expr_ref(t, get_manager()) << "\n";);
source = internalize_term_core(s);
target = internalize_term_core(t);
if (source == null_theory_var || target == null_theory_var) {

View file

@ -733,7 +733,6 @@ theory_var theory_diff_logic<Ext>::mk_term(app* n) {
source = mk_var(a);
for (unsigned i = 0; i < n->get_num_args(); ++i) {
expr* arg = n->get_arg(i);
std::cout << "internalize: " << mk_pp(arg, get_manager()) << " " << ctx.e_internalized(arg) << "\n";
if (!ctx.e_internalized(arg)) {
ctx.internalize(arg, false);
}

View file

@ -119,6 +119,7 @@ namespace smt {
SASSERT(m_conversions.empty());
SASSERT(m_is_added_to_model.empty());
}
void theory_fpa::init(context * ctx) {
smt::theory::init(ctx);
m_is_initialized = true;
@ -255,7 +256,7 @@ namespace smt {
}
func_decl_ref wrap_fd(m);
wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &es, bv_srt);
wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_BVWRAP, 0, 0, 1, &es, bv_srt);
res = m.mk_app(wrap_fd, e);
}
@ -883,26 +884,4 @@ namespace smt {
out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl;
}
}
bool theory_fpa::include_func_interp(func_decl * f) {
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) ||
m_fpa_util.is_max_unspecified(f) ||
m_fpa_util.is_to_ubv_unspecified(f) ||
m_fpa_util.is_to_sbv_unspecified(f) ||
m_fpa_util.is_to_ieee_bv_unspecified(f) ||
m_fpa_util.is_to_real_unspecified(f);
if (include && !m_is_added_to_model.contains(f)) {
m_is_added_to_model.insert(f);
get_manager().inc_ref(f);
return true;
}
return false;
}
else
return true;
}
};

View file

@ -158,7 +158,6 @@ namespace smt {
virtual char const * get_name() const { return "fpa"; }
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
virtual bool include_func_interp(func_decl * f);
void assign_eh(bool_var v, bool is_true);
virtual void relevant_eh(app * n);
@ -179,9 +178,6 @@ namespace smt {
expr_ref convert_atom(expr * e);
expr_ref convert_term(expr * e);
expr_ref convert_conversion_term(expr * e);
expr_ref convert_unwrap(expr * e);
void add_trail(ast * a);
void attach_new_th_var(enode * n);
void assert_cnstr(expr * e);

View file

@ -141,7 +141,7 @@ bool smt_logics::logic_has_fpa(symbol const & s) {
}
bool smt_logics::logic_has_uf(symbol const & s) {
return s == "QF_UF" || s == "UF";
return s == "QF_UF" || s == "UF" || s == "QF_DT";
}
bool smt_logics::logic_has_horn(symbol const& s) {
@ -153,5 +153,5 @@ bool smt_logics::logic_has_pb(symbol const& s) {
}
bool smt_logics::logic_has_datatype(symbol const& s) {
return s == "QF_FD" || s == "ALL";
return s == "QF_FD" || s == "ALL" || s == "QF_DT";
}

View file

@ -392,24 +392,27 @@ struct is_non_nira_functor {
is_non_nira_functor(ast_manager & _m, bool _int, bool _real, bool _quant, bool linear):m(_m), u(m), m_int(_int), m_real(_real), m_quant(_quant), m_linear(linear) {}
void throw_found() {
void throw_found(expr* e) {
TRACE("probe", tout << expr_ref(e, m) << ": " << sort_ref(m.get_sort(e), m) << "\n";);
throw found();
}
void operator()(var * x) {
if (!m_quant)
throw_found();
throw_found(x);
sort * s = x->get_sort();
if (m_int && u.is_int(s))
return;
if (m_real && u.is_real(s))
return;
throw_found();
if (m.is_bool(s))
return;
throw_found(x);
}
void operator()(quantifier *) {
void operator()(quantifier * q) {
if (!m_quant)
throw_found();
throw_found(q);
}
bool compatible_sort(app * n) const {
@ -424,7 +427,7 @@ struct is_non_nira_functor {
void operator()(app * n) {
if (!compatible_sort(n))
throw_found();
throw_found(n);
family_id fid = n->get_family_id();
if (fid == m.get_basic_family_id())
return;
@ -437,39 +440,39 @@ struct is_non_nira_functor {
case OP_MUL:
if (m_linear) {
if (n->get_num_args() != 2)
throw_found();
throw_found(n);
if (!u.is_numeral(n->get_arg(0)))
throw_found();
throw_found(n);
}
return;
case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD:
if (m_linear && !u.is_numeral(n->get_arg(1)))
throw_found();
throw_found(n);
return;
case OP_IS_INT:
if (m_real)
throw_found();
throw_found(n);
return;
case OP_TO_INT:
case OP_TO_REAL:
return;
case OP_POWER:
if (m_linear)
throw_found();
throw_found(n);
return;
case OP_IRRATIONAL_ALGEBRAIC_NUM:
if (m_linear || !m_real)
throw_found();
throw_found(n);
return;
default:
throw_found();
throw_found(n);
}
return;
}
if (is_uninterp_const(n))
return;
throw_found();
throw_found(n);
}
};

View file

@ -33,6 +33,23 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator
}
void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) {
TRACE("fpa2bv_mc", 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;
});
obj_hashtable<func_decl> seen;
m_bv2fp->convert_consts(mc, float_mdl, seen);
m_bv2fp->convert_rm_consts(mc, float_mdl, seen);

157
src/test/argument_parser.h Normal file
View file

@ -0,0 +1,157 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
<name>
Abstract:
<abstract>
Author:
Lev Nachmanson (levnach)
Revision History:
--*/
#include <unordered_map>
#include <vector>
#include <string>
#include <set>
#include <iostream>
namespace lp {
class argument_parser {
std::unordered_map<std::string, std::string> m_options;
std::unordered_map<std::string, std::string> m_options_with_after_string;
std::set<std::string> m_used_options;
std::unordered_map<std::string, std::string> m_used_options_with_after_string;
std::vector<std::string> m_free_args;
std::vector<std::string> m_args;
public:
std::string m_error_message;
argument_parser(unsigned argn, char * const* args) {
for (unsigned i = 0; i < argn; i++) {
m_args.push_back(std::string(args[i]));
}
}
void add_option(std::string s) {
add_option_with_help_string(s, "");
}
void add_option_with_help_string(std::string s, std::string help_string) {
m_options[s]=help_string;
}
void add_option_with_after_string(std::string s) {
add_option_with_after_string_with_help(s, "");
}
void add_option_with_after_string_with_help(std::string s, std::string help_string) {
m_options_with_after_string[s]=help_string;
}
bool parse() {
bool status_is_ok = true;
for (unsigned i = 0; i < m_args.size(); i++) {
std::string ar = m_args[i];
if (m_options.find(ar) != m_options.end() )
m_used_options.insert(ar);
else if (m_options_with_after_string.find(ar) != m_options_with_after_string.end()) {
if (i == m_args.size() - 1) {
m_error_message = "Argument is missing after "+ar;
return false;
}
i++;
m_used_options_with_after_string[ar] = m_args[i];
} else {
if (starts_with(ar, "-") || starts_with(ar, "//"))
status_is_ok = false;
m_free_args.push_back(ar);
}
}
return status_is_ok;
}
bool contains(std::unordered_map<std::string, std::string> & m, std::string s) {
return m.find(s) != m.end();
}
bool contains(std::set<std::string> & m, std::string s) {
return m.find(s) != m.end();
}
bool option_is_used(std::string option) {
return contains(m_used_options, option) || contains(m_used_options_with_after_string, option);
}
std::string get_option_value(std::string option) {
auto t = m_used_options_with_after_string.find(option);
if (t != m_used_options_with_after_string.end()){
return t->second;
}
return std::string();
}
bool starts_with(std::string s, char const * prefix) {
return starts_with(s, std::string(prefix));
}
bool starts_with(std::string s, std::string prefix) {
return s.substr(0, prefix.size()) == prefix;
}
std::string usage_string() {
std::string ret = "";
std::vector<std::string> unknown_options;
for (auto t : m_free_args) {
if (starts_with(t, "-") || starts_with(t, "\\")) {
unknown_options.push_back(t);
}
}
if (unknown_options.size()) {
ret = "Unknown options:";
}
for (auto unknownOption : unknown_options) {
ret += unknownOption;
ret += ",";
}
ret += "\n";
ret += "Usage:\n";
for (auto allowed_option : m_options)
ret += allowed_option.first + " " + (allowed_option.second.size() == 0 ? std::string("") : std::string("/") + allowed_option.second) + std::string("\n");
for (auto s : m_options_with_after_string) {
ret += s.first + " " + (s.second.size() == 0? " \"option value\"":("\""+ s.second+"\"")) + "\n";
}
return ret;
}
void print() {
if (m_used_options.size() == 0 && m_used_options_with_after_string.size() == 0 && m_free_args.size() == 0) {
std::cout << "no options are given" << std::endl;
return;
}
std::cout << "options are: " << std::endl;
for (std::string s : m_used_options) {
std::cout << s << std::endl;
}
for (auto & t : m_used_options_with_after_string) {
std::cout << t.first << " " << t.second << std::endl;
}
if (m_free_args.size() > 0) {
std::cout << "free arguments are: " << std::endl;
for (auto & t : m_free_args) {
std::cout << t << " " << std::endl;
}
}
}
};
}

View file

@ -200,6 +200,20 @@ void tst_ddnf(char ** argv, int argc, int& i) {
dealloc(ddnf);
}
void tst_ddnf1() {
enable_trace("ddnf");
unsigned W = 2;
datalog::ddnf_core ddnf(W);
tbv_manager& tbvm = ddnf.get_tbv_manager();
tbv* tXX = tbvm.allocate("xx");
tbv* t1X = tbvm.allocate("1x");
tbv* tX1 = tbvm.allocate("x1");
tbv* t11 = tbvm.allocate("11");
ddnf.insert(*tXX);
ddnf.insert(*t11);
ddnf.insert(*tX1);
ddnf.insert(*t1X);
ddnf.display(std::cout);
}

3257
src/test/lp.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -238,6 +238,7 @@ int main(int argc, char ** argv) {
TST(sat_user_scope);
TST(pdr);
TST_ARGV(ddnf);
TST(ddnf1);
TST(model_evaluator);
TST(get_consequences);
TST(pb2bv);

409
src/test/smt_reader.h Normal file
View file

@ -0,0 +1,409 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
<name>
Abstract:
<abstract>
Author:
Lev Nachmanson (levnach)
Revision History:
--*/
#pragma once
// reads an MPS file reperesenting a Mixed Integer Program
#include <string>
#include <vector>
#include <unordered_map>
#include "util/lp/lp_primal_simplex.h"
#include "util/lp/lp_dual_simplex.h"
#include "util/lp/lar_solver.h"
#include <iostream>
#include <fstream>
#include <functional>
#include <algorithm>
#include "util/lp/mps_reader.h"
#include "util/lp/ul_pair.h"
#include "util/lp/lar_constraints.h"
#include <sstream>
#include <cstdlib>
namespace lp {
template<typename T>
T from_string(const std::string& str) {
std::istringstream ss(str);
T ret;
ss >> ret;
return ret;
}
class smt_reader {
public:
struct lisp_elem {
std::string m_head;
std::vector<lisp_elem> m_elems;
void print() {
if (m_elems.size()) {
std::cout << '(';
std::cout << m_head << ' ';
for (auto & el : m_elems)
el.print();
std::cout << ')';
} else {
std::cout << " " << m_head;
}
}
unsigned size() const { return static_cast<unsigned>(m_elems.size()); }
bool is_simple() const { return size() == 0; }
};
struct formula_constraint {
lconstraint_kind m_kind;
std::vector<std::pair<mpq, std::string>> m_coeffs;
mpq m_right_side;
void add_pair(mpq c, std::string name) {
m_coeffs.push_back(make_pair(c, name));
}
formula_constraint() : m_right_side(numeric_traits<mpq>::zero()) {}
};
lisp_elem m_formula_lisp_elem;
std::unordered_map<std::string, unsigned> m_name_to_var_index;
std::vector<formula_constraint> m_constraints;
bool m_is_OK;
unsigned m_line_number;
std::string m_file_name;
std::ifstream m_file_stream;
std::string m_line;
smt_reader(std::string file_name):
m_is_OK(true),
m_line_number(0),
m_file_name(file_name),
m_file_stream(file_name) {
}
void set_error() {
std::cout << "setting error" << std::endl;
m_is_OK = false;
}
bool is_ok() {
return m_is_OK;
}
bool prefix(const char * pr) {
return m_line.find(pr) == 0;
}
int first_separator() {
unsigned blank_pos = static_cast<unsigned>(m_line.find(' '));
unsigned br_pos = static_cast<unsigned>(m_line.find('('));
unsigned reverse_br_pos = static_cast<unsigned>(m_line.find(')'));
return std::min(blank_pos, std::min(br_pos, reverse_br_pos));
}
void fill_lisp_elem(lisp_elem & lm) {
if (m_line[0] == '(')
fill_nested_elem(lm);
else
fill_simple_elem(lm);
}
void fill_simple_elem(lisp_elem & lm) {
int separator = first_separator();
SASSERT(-1 != separator && separator != 0);
lm.m_head = m_line.substr(0, separator);
m_line = m_line.substr(separator);
}
void fill_nested_elem(lisp_elem & lm) {
SASSERT(m_line[0] == '(');
m_line = m_line.substr(1);
int separator = first_separator();
lm.m_head = m_line.substr(0, separator);
m_line = m_line.substr(lm.m_head.size());
eat_blanks();
while (m_line.size()) {
if (m_line[0] == '(') {
lisp_elem el;
fill_nested_elem(el);
lm.m_elems.push_back(el);
} else {
if (m_line[0] == ')') {
m_line = m_line.substr(1);
break;
}
lisp_elem el;
fill_simple_elem(el);
lm.m_elems.push_back(el);
}
eat_blanks();
}
}
void eat_blanks() {
while (m_line.size()) {
if (m_line[0] == ' ')
m_line = m_line.substr(1);
else
break;
}
}
void fill_formula_elem() {
fill_lisp_elem(m_formula_lisp_elem);
}
void parse_line() {
if (m_line.find(":formula") == 0) {
int first_br = static_cast<int>(m_line.find('('));
if (first_br == -1) {
std::cout << "empty formula" << std::endl;
return;
}
m_line = m_line.substr(first_br);
fill_formula_elem();
}
}
void set_constraint_kind(formula_constraint & c, lisp_elem & el) {
if (el.m_head == "=") {
c.m_kind = EQ;
} else if (el.m_head == ">=") {
c.m_kind = GE;
} else if (el.m_head == "<=") {
c.m_kind = LE;
} else if (el.m_head == ">") {
c.m_kind = GT;
} else if (el.m_head == "<") {
c.m_kind = LT;
} else {
std::cout << "kind " << el.m_head << " is not supported " << std::endl;
set_error();
}
}
void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) {
// SASSERT(el.m_head == "0"); // do nothing for the time being
}
void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) {
SASSERT(el.m_elems.size() == 2);
set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]);
adjust_rigth_side(c, el.m_elems[1]);
}
bool is_integer(std::string & s) {
if (s.size() == 0) return false;
return atoi(s.c_str()) != 0 || isdigit(s.c_str()[0]);
}
void add_complex_sum_elem(formula_constraint & c, lisp_elem & el) {
if (el.m_head == "*") {
add_mult_elem(c, el.m_elems);
} else if (el.m_head == "~") {
lisp_elem & minel = el.m_elems[0];
SASSERT(minel.is_simple());
c.m_right_side += mpq(str_to_int(minel.m_head));
} else {
std::cout << "unexpected input " << el.m_head << std::endl;
set_error();
return;
}
}
std::string get_name(lisp_elem & name) {
SASSERT(name.is_simple());
SASSERT(!is_integer(name.m_head));
return name.m_head;
}
void add_mult_elem(formula_constraint & c, std::vector<lisp_elem> & els) {
SASSERT(els.size() == 2);
mpq coeff = get_coeff(els[0]);
std::string col_name = get_name(els[1]);
c.add_pair(coeff, col_name);
}
mpq get_coeff(lisp_elem & le) {
if (le.is_simple()) {
return mpq(str_to_int(le.m_head));
} else {
SASSERT(le.m_head == "~");
SASSERT(le.size() == 1);
lisp_elem & el = le.m_elems[0];
SASSERT(el.is_simple());
return -mpq(str_to_int(el.m_head));
}
}
int str_to_int(std::string & s) {
SASSERT(is_integer(s));
return atoi(s.c_str());
}
void add_sum_elem(formula_constraint & c, lisp_elem & el) {
if (el.size()) {
add_complex_sum_elem(c, el);
} else {
SASSERT(is_integer(el.m_head));
int v = atoi(el.m_head.c_str());
mpq vr(v);
c.m_right_side -= vr;
}
}
void add_sum(formula_constraint & c, std::vector<lisp_elem> & sum_els) {
for (auto & el : sum_els)
add_sum_elem(c, el);
}
void set_constraint_coeffs_on_coeff_element(formula_constraint & c, lisp_elem & el) {
if (el.m_head == "*") {
add_mult_elem(c, el.m_elems);
} else if (el.m_head == "+") {
add_sum(c, el.m_elems);
} else {
SASSERT(false); // unexpected input
}
}
void create_constraint(lisp_elem & el) {
formula_constraint c;
set_constraint_kind(c, el);
set_constraint_coeffs(c, el);
m_constraints.push_back(c);
}
void fill_constraints() {
if (m_formula_lisp_elem.m_head != "and") {
std::cout << "unexpected top element " << m_formula_lisp_elem.m_head << std::endl;
set_error();
return;
}
for (auto & el : m_formula_lisp_elem.m_elems)
create_constraint(el);
}
void read() {
if (!m_file_stream.is_open()){
std::cout << "cannot open file " << m_file_name << std::endl;
set_error();
return;
}
while (m_is_OK && getline(m_file_stream, m_line)) {
parse_line();
m_line_number++;
}
m_file_stream.close();
fill_constraints();
}
/*
void fill_lar_solver_on_row(row * row, lar_solver *solver) {
if (row->m_name != m_cost_row_name) {
lar_constraint c(get_lar_relation_from_row(row->m_type), row->m_right_side);
for (auto s : row->m_row_columns) {
var_index i = solver->add_var(s.first);
c.add_variable_to_constraint(i, s.second);
}
solver->add_constraint(&c);
} else {
// ignore the cost row
}
}
void fill_lar_solver_on_rows(lar_solver * solver) {
for (auto row_it : m_rows) {
fill_lar_solver_on_row(row_it.second, solver);
}
}
void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) {
lar_constraint c(GE, b->m_low);
var_index i = solver->add_var(col->m_name);
c.add_variable_to_constraint(i, numeric_traits<T>::one());
solver->add_constraint(&c);
}
void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) {
lar_constraint c(LE, b->m_upper);
var_index i = solver->add_var(col->m_name);
c.add_variable_to_constraint(i, numeric_traits<T>::one());
solver->add_constraint(&c);
}
void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) {
lar_constraint c(EQ, b->m_fixed_value);
var_index i = solver->add_var(col->m_name);
c.add_variable_to_constraint(i, numeric_traits<T>::one());
solver->add_constraint(&c);
}
void fill_lar_solver_on_columns(lar_solver * solver) {
for (auto s : m_columns) {
mps_reader::column * col = s.second;
solver->add_var(col->m_name);
auto b = col->m_bound;
if (b == nullptr) return;
if (b->m_free) continue;
if (b->m_low_is_set) {
create_low_constraint_for_var(col, b, solver);
}
if (b->m_upper_is_set) {
create_upper_constraint_for_var(col, b, solver);
}
if (b->m_value_is_fixed) {
create_equality_contraint_for_var(col, b, solver);
}
}
}
*/
unsigned register_name(std::string s) {
auto it = m_name_to_var_index.find(s);
if (it!= m_name_to_var_index.end())
return it->second;
unsigned ret = static_cast<unsigned>(m_name_to_var_index.size());
m_name_to_var_index[s] = ret;
return ret;
}
void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc) {
vector<std::pair<mpq, var_index>> ls;
for (auto & it : fc.m_coeffs) {
ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second))));
}
solver->add_constraint(ls, fc.m_kind, fc.m_right_side);
}
void fill_lar_solver(lar_solver * solver) {
for (formula_constraint & fc : m_constraints)
add_constraint_to_solver(solver, fc);
}
lar_solver * create_lar_solver() {
lar_solver * ls = new lar_solver();
fill_lar_solver(ls);
return ls;
}
};
}

View file

@ -15,8 +15,6 @@ Copyright (c) 2015 Microsoft Corporation
#include "smt/smt_kernel.h"
#include "smt/params/smt_params.h"
struct ast_ext {
ast_manager& m;
ast_ext(ast_manager& m):m(m) {}

View file

@ -0,0 +1,87 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
<name>
Abstract:
<abstract>
Author:
Lev Nachmanson (levnach)
Revision History:
--*/
#pragma once
// reads a text file
#include <string>
#include <vector>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include "util/lp/lp_utils.h"
#include "util/lp/lp_solver.h"
namespace lp {
template <typename T>
struct test_result {
lp_status m_status;
T m_cost;
std::unordered_map<std::string, T> column_values;
};
template <typename T>
class test_file_reader {
struct raw_blob {
std::vector<std::string> m_unparsed_strings;
std::vector<raw_blob> m_blobs;
};
struct test_file_blob {
std::string m_name;
std::string m_content;
std::unordered_map<std::string, std::string> m_table;
std::unordered_map<std::string, test_file_blob> m_blobs;
test_result<T> * get_test_result() {
test_result<T> * tr = new test_result<T>();
throw "not impl";
return tr;
}
};
std::ifstream m_file_stream;
public:
// constructor
test_file_reader(std::string file_name) : m_file_stream(file_name) {
if (!m_file_stream.is_open()) {
std::cout << "cannot open file " << "\'" << file_name << "\'" << std::endl;
}
}
raw_blob scan_to_row_blob() {
}
test_file_blob scan_row_blob_to_test_file_blob(raw_blob /* rblob */) {
}
test_result<T> * get_test_result() {
if (!m_file_stream.is_open()) {
return nullptr;
}
raw_blob rblob = scan_to_row_blob();
test_file_blob tblob = scan_row_blob_to_test_file_blob(rblob);
return tblob.get_test_result();
}
};
}

View file

@ -1,392 +0,0 @@
/*
Copyright (c) 2017 Microsoft Corporation
Author: Lev Nachmanson
*/
// this is a part of lp_primal_core_solver that deals with the tableau
#include "util/lp/lp_primal_core_solver.h"
namespace lp {
template <typename T, typename X> void lp_primal_core_solver<T, X>::one_iteration_tableau() {
int entering = choose_entering_column_tableau();
if (entering == -1) {
decide_on_status_when_cannot_find_entering();
}
else {
advance_on_entering_tableau(entering);
}
lp_assert(this->inf_set_is_correct());
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_entering_tableau(int entering) {
X t;
int leaving = find_leaving_and_t_tableau(entering, t);
if (leaving == -1) {
this->set_status(lp_status::UNBOUNDED);
return;
}
advance_on_entering_and_leaving_tableau(entering, leaving, t);
}
/*
template <typename T, typename X> int lp_primal_core_solver<T, X>::choose_entering_column_tableau_rows() {
int i = find_inf_row();
if (i == -1)
return -1;
return find_shortest_beneficial_column_in_row(i);
}
*/
template <typename T, typename X> int lp_primal_core_solver<T, X>::choose_entering_column_tableau() {
//this moment m_y = cB * B(-1)
unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter();
lp_assert(numeric_traits<T>::precise());
if (number_of_benefitial_columns_to_go_over == 0)
return -1;
if (this->m_basis_sort_counter == 0) {
sort_non_basis();
this->m_basis_sort_counter = 20;
}
else {
this->m_basis_sort_counter--;
}
unsigned j_nz = this->m_m() + 1; // this number is greater than the max column size
std::list<unsigned>::iterator entering_iter = m_non_basis_list.end();
for (auto non_basis_iter = m_non_basis_list.begin(); number_of_benefitial_columns_to_go_over && non_basis_iter != m_non_basis_list.end(); ++non_basis_iter) {
unsigned j = *non_basis_iter;
if (!column_is_benefitial_for_entering_basis(j))
continue;
// if we are here then j is a candidate to enter the basis
unsigned t = this->m_A.number_of_non_zeroes_in_column(j);
if (t < j_nz) {
j_nz = t;
entering_iter = non_basis_iter;
if (number_of_benefitial_columns_to_go_over)
number_of_benefitial_columns_to_go_over--;
}
else if (t == j_nz && this->m_settings.random_next() % 2 == 0) {
entering_iter = non_basis_iter;
}
}// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb);
if (entering_iter == m_non_basis_list.end())
return -1;
unsigned entering = *entering_iter;
m_sign_of_entering_delta = this->m_d[entering] > 0 ? 1 : -1;
if (this->m_using_infeas_costs && this->m_settings.use_breakpoints_in_feasibility_search)
m_sign_of_entering_delta = -m_sign_of_entering_delta;
m_non_basis_list.erase(entering_iter);
m_non_basis_list.push_back(entering);
return entering;
}
template <typename T, typename X>
unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
init_run_tableau();
if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) {
this->set_status(lp_status::FEASIBLE);
return 0;
}
if ((!numeric_traits<T>::precise()) && this->A_mult_x_is_off()) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
return 0;
}
do {
if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over((this->m_using_infeas_costs? "inf t" : "feas t"), * this->m_settings.get_message_ostream())) {
return this->total_iterations();
}
if (this->m_settings.use_tableau_rows()) {
one_iteration_tableau_rows();
}
else
one_iteration_tableau();
switch (this->get_status()) {
case lp_status::OPTIMAL: // double check that we are at optimum
case lp_status::INFEASIBLE:
if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible())
break;
if (!numeric_traits<T>::precise()) {
if(this->m_look_for_feasible_solution_only)
break;
this->init_lu();
if (this->m_factorization->get_status() != LU_status::OK) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
break;
}
init_reduced_costs();
if (choose_entering_column(1) == -1) {
decide_on_status_when_cannot_find_entering();
break;
}
this->set_status(lp_status::UNKNOWN);
} else { // precise case
if ((!this->infeasibility_costs_are_correct())) {
init_reduced_costs_tableau(); // forcing recalc
if (choose_entering_column_tableau() == -1) {
decide_on_status_when_cannot_find_entering();
break;
}
this->set_status(lp_status::UNKNOWN);
}
}
break;
case lp_status::TENTATIVE_UNBOUNDED:
this->init_lu();
if (this->m_factorization->get_status() != LU_status::OK) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
break;
}
init_reduced_costs();
break;
case lp_status::UNBOUNDED:
if (this->current_x_is_infeasible()) {
init_reduced_costs();
this->set_status(lp_status::UNKNOWN);
}
break;
case lp_status::UNSTABLE:
lp_assert(! (numeric_traits<T>::precise()));
this->init_lu();
if (this->m_factorization->get_status() != LU_status::OK) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
break;
}
init_reduced_costs();
break;
default:
break; // do nothing
}
} while (this->get_status() != lp_status::FLOATING_POINT_ERROR
&&
this->get_status() != lp_status::UNBOUNDED
&&
this->get_status() != lp_status::OPTIMAL
&&
this->get_status() != lp_status::INFEASIBLE
&&
this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
&&
this->total_iterations() <= this->m_settings.max_total_number_of_iterations
&&
!(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only));
lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR
||
this->current_x_is_feasible() == false
||
this->calc_current_x_is_feasible_include_non_basis());
return this->total_iterations();
}
template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) {
CASSERT("A_off", this->A_mult_x_is_off() == false);
lp_assert(leaving >= 0 && entering >= 0);
lp_assert((this->m_settings.simplex_strategy() ==
simplex_strategy_enum::tableau_rows) ||
m_non_basis_list.back() == static_cast<unsigned>(entering));
lp_assert(this->m_using_infeas_costs || !is_neg(t));
lp_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes
if (entering == leaving) {
advance_on_entering_equal_leaving_tableau(entering, t);
return;
}
if (!is_zero(t)) {
if (this->current_x_is_feasible() || !this->m_settings.use_breakpoints_in_feasibility_search ) {
if (m_sign_of_entering_delta == -1)
t = -t;
}
this->update_basis_and_x_tableau(entering, leaving, t);
CASSERT("A_off", this->A_mult_x_is_off() == false);
this->iters_with_no_cost_growing() = 0;
} else {
this->pivot_column_tableau(entering, this->m_basis_heading[leaving]);
this->change_basis(entering, leaving);
}
if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible())
return;
if (this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows) {
if (need_to_switch_costs()) {
this->init_reduced_costs_tableau();
}
lp_assert(!need_to_switch_costs());
std::list<unsigned>::iterator it = m_non_basis_list.end();
it--;
* it = static_cast<unsigned>(leaving);
}
}
template <typename T, typename X>
void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving_tableau(int entering, X & t) {
CASSERT("A_off", !this->A_mult_x_is_off() );
this->update_x_tableau(entering, t * m_sign_of_entering_delta);
if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible())
return;
if (need_to_switch_costs()) {
init_reduced_costs_tableau();
}
this->iters_with_no_cost_growing() = 0;
}
template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_and_t_tableau(unsigned entering, X & t) {
unsigned k = 0;
bool unlimited = true;
unsigned row_min_nz = this->m_n() + 1;
m_leaving_candidates.clear();
auto & col = this->m_A.m_columns[entering];
unsigned col_size = col.size();
for (;k < col_size && unlimited; k++) {
const column_cell & c = col[k];
unsigned i = c.m_i;
const T & ed = this->m_A.get_val(c);
lp_assert(!numeric_traits<T>::is_zero(ed));
unsigned j = this->m_basis[i];
limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited);
if (!unlimited) {
m_leaving_candidates.push_back(j);
row_min_nz = this->m_A.m_rows[i].size();
}
}
if (unlimited) {
if (try_jump_to_another_bound_on_entering_unlimited(entering, t))
return entering;
return -1;
}
X ratio;
for (;k < col_size; k++) {
const column_cell & c = col[k];
unsigned i = c.m_i;
const T & ed = this->m_A.get_val(c);
lp_assert(!numeric_traits<T>::is_zero(ed));
unsigned j = this->m_basis[i];
unlimited = true;
limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited);
if (unlimited) continue;
unsigned i_nz = this->m_A.m_rows[i].size();
if (ratio < t) {
t = ratio;
m_leaving_candidates.clear();
m_leaving_candidates.push_back(j);
row_min_nz = i_nz;
} else if (ratio == t && i_nz < row_min_nz) {
m_leaving_candidates.clear();
m_leaving_candidates.push_back(j);
row_min_nz = this->m_A.m_rows[i].size();
} else if (ratio == t && i_nz == row_min_nz) {
m_leaving_candidates.push_back(j);
}
}
ratio = t;
unlimited = false;
if (try_jump_to_another_bound_on_entering(entering, t, ratio, unlimited)) {
t = ratio;
return entering;
}
if (m_leaving_candidates.size() == 1)
return m_leaving_candidates[0];
k = this->m_settings.random_next() % m_leaving_candidates.size();
return m_leaving_candidates[k];
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tableau() {
// print_matrix(&(this->m_A), std::cout);
CASSERT("A_off", this->A_mult_x_is_off() == false);
lp_assert(basis_columns_are_set_correctly());
this->m_basis_sort_counter = 0; // to initiate the sort of the basis
this->set_total_iterations(0);
this->iters_with_no_cost_growing() = 0;
lp_assert(this->inf_set_is_correct());
if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
return;
if (this->m_settings.backup_costs)
backup_and_normalize_costs();
m_epsilon_of_reduced_cost = numeric_traits<X>::precise() ? zero_of_type<T>() : T(1) / T(10000000);
if (this->m_settings.use_breakpoints_in_feasibility_search)
m_breakpoint_indices_queue.resize(this->m_n());
if (!numeric_traits<X>::precise()) {
this->m_column_norm_update_counter = 0;
init_column_norms();
}
if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows)
init_tableau_rows();
lp_assert(this->reduced_costs_are_correct_tableau());
lp_assert(!this->need_to_pivot_to_basis_tableau());
}
template <typename T, typename X> bool lp_primal_core_solver<T, X>::
update_basis_and_x_tableau(int entering, int leaving, X const & tt) {
lp_assert(this->use_tableau());
update_x_tableau(entering, tt);
this->pivot_column_tableau(entering, this->m_basis_heading[leaving]);
this->change_basis(entering, leaving);
return true;
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::
update_x_tableau(unsigned entering, const X& delta) {
this->add_delta_to_x_and_call_tracker(entering, delta);
if (!this->m_using_infeas_costs) {
for (const auto & c : this->m_A.m_columns[entering]) {
unsigned i = c.m_i;
this->update_x_with_delta_and_track_feasibility(this->m_basis[i], - delta * this->m_A.get_val(c));
}
} else { // m_using_infeas_costs == true
lp_assert(this->column_is_feasible(entering));
lp_assert(this->m_costs[entering] == zero_of_type<T>());
// m_d[entering] can change because of the cost change for basic columns.
for (const auto & c : this->m_A.m_columns[entering]) {
unsigned i = c.m_i;
unsigned j = this->m_basis[i];
this->add_delta_to_x_and_call_tracker(j, -delta * this->m_A.get_val(c));
update_inf_cost_for_column_tableau(j);
if (is_zero(this->m_costs[j]))
this->remove_column_from_inf_set(j);
else
this->insert_column_into_inf_set(j);
}
}
CASSERT("A_off", this->A_mult_x_is_off() == false);
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::
update_inf_cost_for_column_tableau(unsigned j) {
lp_assert(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows);
lp_assert(this->m_using_infeas_costs);
T new_cost = get_infeasibility_cost_for_column(j);
T delta = this->m_costs[j] - new_cost;
if (is_zero(delta))
return;
this->m_costs[j] = new_cost;
update_reduced_cost_for_basic_column_cost_change(delta, j);
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_reduced_costs_tableau() {
if (this->current_x_is_infeasible() && !this->m_using_infeas_costs) {
init_infeasibility_costs();
} else if (this->current_x_is_feasible() && this->m_using_infeas_costs) {
if (this->m_look_for_feasible_solution_only)
return;
this->m_costs = m_costs_backup;
this->m_using_infeas_costs = false;
}
unsigned size = this->m_basis_heading.size();
for (unsigned j = 0; j < size; j++) {
if (this->m_basis_heading[j] >= 0)
this->m_d[j] = zero_of_type<T>();
else {
T& d = this->m_d[j] = this->m_costs[j];
for (auto & cc : this->m_A.m_columns[j]) {
d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc);
}
}
}
}
}

View file

@ -1217,12 +1217,18 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o
default: UNREACHABLE();
}
if (inc) m_mpz_manager.inc(z);
TRACE("mpf_dbg_sbv",
tout << "SBV: (" << to_string(x) << ") == " << m_mpq_manager.to_string(z) << std::endl;
tout << "sign=" << t.sign() << " last=" << last << " round=" << round <<
" sticky=" << sticky << " inc=" << inc << std::endl; );
}
else
m_mpz_manager.mul2k(z, (unsigned) e);
m_mpq_manager.set(o, z);
if (x.sign) m_mpq_manager.neg(o);
TRACE("mpf_dbg", tout << "SBV = " << m_mpq_manager.to_string(o) << std::endl;);
}
void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) {
@ -1248,6 +1254,8 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) {
m_mpz_manager.mul2k(o, sbits - 1);
m_mpz_manager.add(o, sig(x), o);
}
TRACE("mpf_dbg", tout << "IEEE_BV = " << m_mpz_manager.to_string(o) << std::endl;);
}
void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig) {