Skip to content

Commit 2308d8a

Browse files
author
Christoph M. Wintersteiger
committed
Fix for partially interpreted floating-point functions. Relates to #2596, #2631.
1 parent 1d4f8c0 commit 2308d8a

7 files changed

+118
-86
lines changed

src/ast/fpa/bv2fpa_converter.cpp

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,10 @@ bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) :
5151
for (auto const& kv : conv.m_uf2bvuf) {
5252
m_uf2bvuf.insert(kv.m_key, kv.m_value);
5353
m.inc_ref(kv.m_key);
54-
m.inc_ref(kv.m_value.first);
55-
m.inc_ref(kv.m_value.second);
54+
m.inc_ref(kv.m_value);
5655
}
5756
for (auto const& kv : conv.m_min_max_ufs) {
58-
m_specials.insert(kv.m_key, kv.m_value);
57+
m_min_max_specials.insert(kv.m_key, kv.m_value);
5958
m.inc_ref(kv.m_key);
6059
m.inc_ref(kv.m_value.first);
6160
m.inc_ref(kv.m_value.second);
@@ -67,16 +66,15 @@ bv2fpa_converter::~bv2fpa_converter() {
6766
dec_ref_map_key_values(m, m_rm_const2bv);
6867
for (auto const& kv : m_uf2bvuf) {
6968
m.dec_ref(kv.m_key);
70-
m.dec_ref(kv.m_value.first);
71-
m.dec_ref(kv.m_value.second);
69+
m.dec_ref(kv.m_value);
7270
}
73-
for (auto const& kv : m_specials) {
71+
for (auto const& kv : m_min_max_specials) {
7472
m.dec_ref(kv.m_key);
7573
m.dec_ref(kv.m_value.first);
7674
m.dec_ref(kv.m_value.second);
7775
}
7876
m_uf2bvuf.reset();
79-
m_specials.reset();
77+
m_min_max_specials.reset();
8078
}
8179

8280
expr_ref bv2fpa_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) {
@@ -191,7 +189,7 @@ expr_ref bv2fpa_converter::convert_bv2rm(model_core * mc, expr * val) {
191189

192190
expr_ref bv2fpa_converter::rebuild_floats(model_core * mc, sort * s, expr * e) {
193191
expr_ref result(m);
194-
TRACE("bv2fpa", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for ";
192+
TRACE("bv2fpa_rebuild", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for ";
195193
if (e) tout << mk_ismt2_pp(e, m);
196194
else tout << "nil";
197195
tout << std::endl; );
@@ -288,13 +286,23 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl *
288286
expr_ref ft_fres = rebuild_floats(mc, rng, to_app(bv_fres));
289287
m_th_rw(ft_fres);
290288
TRACE("bv2fpa",
289+
tout << "func_interp entry #" << i << ":" << std::endl;
290+
tout << "(" << bv_f->get_name();
291+
for (unsigned i = 0; i < bv_f->get_arity(); i++)
292+
tout << " " << mk_ismt2_pp(bv_args[i], m);
293+
tout << ") = " << mk_ismt2_pp(bv_fres, m) << std::endl;
294+
tout << " --> " << std::endl;
295+
tout << "(" << f->get_name();
291296
for (unsigned i = 0; i < new_args.size(); i++)
292-
tout << mk_ismt2_pp(bv_args[i], m) << " == " <<
293-
mk_ismt2_pp(new_args[i], m) << std::endl;
294-
tout << mk_ismt2_pp(bv_fres, m) << " == " << mk_ismt2_pp(ft_fres, m) << std::endl;);
297+
tout << " " << mk_ismt2_pp(new_args[i], m);
298+
tout << ") = " << mk_ismt2_pp(ft_fres, m) << std::endl;);
295299
func_entry * fe = result->get_entry(new_args.c_ptr());
296-
if (fe == nullptr)
297-
result->insert_new_entry(new_args.c_ptr(), ft_fres);
300+
if (fe == nullptr) {
301+
// Avoid over-specification of a partially interpreted theory function
302+
if (f->get_family_id() != m_fpa_util.get_family_id() ||
303+
m_fpa_util.is_considered_uninterpreted(f, new_args.size(), new_args.c_ptr()))
304+
result->insert_new_entry(new_args.c_ptr(), ft_fres);
305+
}
298306
else {
299307
// The BV model may have multiple equivalent entries using different
300308
// representations of NaN. We can only keep one and we check that
@@ -309,6 +317,7 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl *
309317
if (bv_els) {
310318
expr_ref ft_els = rebuild_floats(mc, rng, bv_els);
311319
m_th_rw(ft_els);
320+
TRACE("bv2fpa", tout << "else=" << mk_ismt2_pp(ft_els, m) << std::endl;);
312321
result->set_else(ft_els);
313322
}
314323
}
@@ -398,7 +407,7 @@ void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_mo
398407
}
399408

400409
void bv2fpa_converter::convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
401-
for (auto const& kv : m_specials) {
410+
for (auto const& kv : m_min_max_specials) {
402411
func_decl * f = kv.m_key;
403412
app * pn_cnst = kv.m_value.first;
404413
app * np_cnst = kv.m_value.second;
@@ -432,8 +441,7 @@ void bv2fpa_converter::convert_min_max_specials(model_core * mc, model_core * ta
432441
void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
433442
for (auto const& kv : m_uf2bvuf) {
434443
func_decl * f = kv.m_key;
435-
func_decl* f_uf = kv.m_value.first;
436-
expr* f_def = kv.m_value.second;
444+
func_decl * f_uf = kv.m_value;
437445
seen.insert(f_uf);
438446

439447
if (f->get_arity() == 0)
@@ -454,29 +462,22 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode
454462
}
455463
}
456464
else if (f->get_family_id() == m_fpa_util.get_fid()) {
457-
if (f_def) {
458-
func_interp* fi = alloc(func_interp, m, f->get_arity());
459-
expr_ref def = rebuild_floats(mc, f->get_range(), to_app(f_def));
460-
fi->set_else(def);
461-
SASSERT(m.get_sort(def) == f->get_range());
462-
target_model->register_decl(f, fi);
463-
func_interp* fj = mc->get_func_interp(f_uf);
464-
if (fj) {
465-
target_model->register_decl(f_uf, fj->copy());
466-
}
467-
continue;
468-
}
469-
465+
// kv.m_value contains the model for the unspecified cases of kv.m_key in terms of bit-vectors.
466+
// convert_func_interp rebuilds a func_interp on floats.
470467

471468
// f is a floating point function: f(x,y) : Float
472469
// f_uf is a bit-vector function: f_uf(xB,yB) : BitVec
473470
// then there is f_def: f_Bv(xB, yB) := if(range(xB),.., f_uf(xB,yB))
474471
// f(x,y) := to_float(if(range(to_bv(x)), ... f_uf(to_bv(xB), to_bv(yB)))) - not practical
475-
// := if(range_fp(x), ...., to_float(f_uf(...)) - approach
476-
477-
target_model->register_decl(f, convert_func_interp(mc, f, f_uf));
472+
// := if(range_fp(x), ...., to_float(f_uf(...)) - approach (via fpa_util::is_considered_uninterpreted)
473+
474+
func_interp *fi = convert_func_interp(mc, f, f_uf);
475+
if (fi->num_entries() > 0 || fi->get_else() != nullptr)
476+
target_model->register_decl(f, fi);
478477
}
479478
}
479+
480+
TRACE("bv2fpa", tout << "Target model: " << *target_model; );
480481
}
481482

482483
void bv2fpa_converter::display(std::ostream & out) {
@@ -496,9 +497,9 @@ void bv2fpa_converter::display(std::ostream & out) {
496497
const symbol & n = kv.m_key->get_name();
497498
out << "\n (" << n << " ";
498499
unsigned indent = n.size() + 4;
499-
out << mk_ismt2_pp(kv.m_value.first, m, indent) << ")";
500+
out << mk_ismt2_pp(kv.m_value, m, indent) << ")";
500501
}
501-
for (auto const& kv : m_specials) {
502+
for (auto const& kv : m_min_max_specials) {
502503
const symbol & n = kv.m_key->get_name();
503504
out << "\n (" << n << " ";
504505
unsigned indent = n.size() + 4;
@@ -525,22 +526,19 @@ bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) {
525526
}
526527
for (auto const& kv : m_uf2bvuf) {
527528
func_decl * k = translator(kv.m_key);
528-
func_decl * v = translator(kv.m_value.first);
529-
expr* d = translator(kv.m_value.second);
530-
res->m_uf2bvuf.insert(k, std::make_pair(v, d));
529+
func_decl * v = translator(kv.m_value);
530+
res->m_uf2bvuf.insert(k, v);
531531
translator.to().inc_ref(k);
532532
translator.to().inc_ref(v);
533-
translator.to().inc_ref(d);
534533
}
535-
for (auto const& kv : m_specials) {
534+
for (auto const& kv : m_min_max_specials) {
536535
func_decl * k = translator(kv.m_key);
537536
app * v1 = translator(kv.m_value.first);
538537
app * v2 = translator(kv.m_value.second);
539-
res->m_specials.insert(k, std::pair<app*, app*>(v1, v2));
538+
res->m_min_max_specials.insert(k, std::pair<app*, app*>(v1, v2));
540539
translator.to().inc_ref(k);
541540
translator.to().inc_ref(v1);
542541
translator.to().inc_ref(v2);
543542
}
544543
return res;
545544
}
546-

src/ast/fpa/bv2fpa_converter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ class bv2fpa_converter {
3434

3535
obj_map<func_decl, expr*> m_const2bv;
3636
obj_map<func_decl, expr*> m_rm_const2bv;
37-
obj_map<func_decl, std::pair<func_decl*, expr*>> m_uf2bvuf;
38-
obj_map<func_decl, std::pair<app*, app*> > m_specials;
37+
obj_map<func_decl, func_decl*> m_uf2bvuf;
38+
obj_map<func_decl, std::pair<app*, app*> > m_min_max_specials;
3939

4040
public:
4141
bv2fpa_converter(ast_manager & m);

src/ast/fpa/fpa2bv_converter.cpp

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,7 +3203,6 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
32033203

32043204
expr_ref sgn(m), sig(m), exp(m), lz(m);
32053205
unpack(x, sgn, sig, exp, lz, true);
3206-
32073206

32083207
unsigned ebits = m_util.get_ebits(xs);
32093208
unsigned sbits = m_util.get_sbits(xs);
@@ -4166,8 +4165,7 @@ void fpa2bv_converter::reset() {
41664165
dec_ref_map_key_values(m, m_rm_const2bv);
41674166
for (auto const& kv : m_uf2bvuf) {
41684167
m.dec_ref(kv.m_key);
4169-
m.dec_ref(kv.m_value.first);
4170-
m.dec_ref(kv.m_value.second);
4168+
m.dec_ref(kv.m_value);
41714169
}
41724170
for (auto const& kv : m_min_max_ufs) {
41734171
m.dec_ref(kv.m_key);
@@ -4180,36 +4178,13 @@ void fpa2bv_converter::reset() {
41804178
}
41814179

41824180
func_decl * fpa2bv_converter::mk_bv_uf(func_decl * f, sort * const * domain, sort * range) {
4183-
std::pair<func_decl*, expr*> res;
4181+
func_decl* res;
41844182
if (!m_uf2bvuf.find(f, res)) {
4185-
res.first = m.mk_fresh_func_decl(nullptr, f->get_arity(), domain, range);
4186-
res.second = nullptr;
4183+
res = m.mk_fresh_func_decl(nullptr, f->get_arity(), domain, range);
41874184
m.inc_ref(f);
4188-
m.inc_ref(res.first);
4185+
m.inc_ref(res);
41894186
m_uf2bvuf.insert(f, res);
4190-
TRACE("fpa2bv", tout << "New UF func_decl: " << res.first->get_id() << std::endl << mk_ismt2_pp(res.first, m) << std::endl;);
4187+
TRACE("fpa2bv", tout << "New UF func_decl: " << res->get_id() << std::endl << mk_ismt2_pp(res, m) << std::endl;);
41914188
}
4192-
return res.first;
4193-
}
4194-
4195-
expr* fpa2bv_converter::get_bv_def(func_decl* f) {
4196-
std::pair<func_decl*, expr*> res(nullptr, nullptr);
4197-
m_uf2bvuf.find(f, res);
4198-
TRACE("fpa2bv", tout << "get_bv_def " << mk_ismt2_pp(res.first, m) << " " << res.second << std::endl;);
4199-
return res.second;
4200-
}
4201-
4202-
/**
4203-
\brief expand the definition of bit-vector function f
4204-
as an expression of what is defined and what is not
4205-
defined.
4206-
*/
4207-
void fpa2bv_converter::set_bv_def(func_decl* f, expr* def) {
4208-
auto res = m_uf2bvuf[f];
4209-
SASSERT(res.first);
4210-
SASSERT(!res.second);
4211-
res.second = def;
4212-
m.inc_ref(def);
4213-
m_uf2bvuf.insert(f, res);
4214-
4189+
return res;
42154190
}

src/ast/fpa/fpa2bv_converter.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class fpa2bv_converter {
3535
public:
3636
typedef obj_map<func_decl, std::pair<app *, app *> > special_t;
3737
typedef obj_map<func_decl, expr*> const2bv_t;
38-
typedef obj_map<func_decl, std::pair<func_decl*, expr*> > uf2bvuf_t;
38+
typedef obj_map<func_decl, func_decl*> uf2bvuf_t;
3939

4040
protected:
4141
ast_manager & m;
@@ -219,8 +219,6 @@ class fpa2bv_converter {
219219
void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result);
220220

221221
func_decl * mk_bv_uf(func_decl * f, sort * const * domain, sort * range);
222-
void set_bv_def(func_decl * f, expr* def);
223-
expr* get_bv_def(func_decl * f);
224222

225223
expr_ref nan_wrap(expr * n);
226224

src/ast/fpa_decl_plugin.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Revision History:
1919
#include "ast/fpa_decl_plugin.h"
2020
#include "ast/arith_decl_plugin.h"
2121
#include "ast/bv_decl_plugin.h"
22+
#include "ast/ast_smt2_pp.h"
2223

2324
fpa_decl_plugin::fpa_decl_plugin():
2425
m_values(m_fm),
@@ -68,6 +69,10 @@ void fpa_decl_plugin::recycled_id(unsigned id) {
6869
m_fm.del(m_values[id]);
6970
}
7071

72+
bool fpa_decl_plugin::is_considered_uninterpreted(func_decl * f) {
73+
return false;
74+
}
75+
7176
func_decl * fpa_decl_plugin::mk_numeral_decl(mpf const & v) {
7277
sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
7378
func_decl * r = nullptr;
@@ -1044,3 +1049,44 @@ bool fpa_util::contains_floats(ast * a) {
10441049

10451050
return false;
10461051
}
1052+
1053+
bool fpa_util::is_considered_uninterpreted(func_decl * f, unsigned n, expr* const* args) {
1054+
TRACE("fpa_util", expr_ref t(m().mk_app(f, n, args), m()); tout << mk_ismt2_pp(t, m()) << std::endl; );
1055+
1056+
family_id ffid = plugin().get_family_id();
1057+
if (f->get_family_id() != ffid)
1058+
return false;
1059+
1060+
if (is_decl_of(f, ffid, OP_FPA_TO_IEEE_BV)) {
1061+
SASSERT(n == 1);
1062+
expr* x = args[0];
1063+
return is_nan(x);
1064+
}
1065+
else if (is_decl_of(f, ffid, OP_FPA_TO_SBV) ||
1066+
is_decl_of(f, ffid, OP_FPA_TO_UBV)) {
1067+
SASSERT(n == 2);
1068+
SASSERT(f->get_num_parameters() == 1);
1069+
bool is_signed = f->get_decl_kind() == OP_FPA_TO_SBV;
1070+
expr* rm = args[0];
1071+
expr* x = args[1];
1072+
unsigned bv_sz = f->get_parameter(0).get_int();
1073+
mpf_rounding_mode rmv;
1074+
mpf v;
1075+
if (!is_rm_numeral(rm, rmv) || !is_numeral(x, v)) return false;
1076+
if (is_nan(x) || is_inf(x)) return true;
1077+
unsynch_mpq_manager& mpqm = plugin().fm().mpq_manager();
1078+
scoped_mpq r(mpqm);
1079+
plugin().fm().to_sbv_mpq(rmv, v, r);
1080+
if (is_signed)
1081+
return mpqm.bitsize(r) >= bv_sz;
1082+
else
1083+
return mpqm.is_neg(r) || mpqm.bitsize(r) > bv_sz;
1084+
}
1085+
else if (is_decl_of(f, ffid, OP_FPA_TO_REAL)) {
1086+
SASSERT(n == 1);
1087+
expr* x = args[0];
1088+
return is_nan(x) || is_inf(x);
1089+
}
1090+
1091+
return plugin().is_considered_uninterpreted(f);
1092+
}

src/ast/fpa_decl_plugin.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,6 @@ class fpa_decl_plugin : public decl_plugin {
163163
unsigned mk_id(mpf const & v);
164164
void recycled_id(unsigned id);
165165

166-
bool is_considered_uninterpreted(func_decl * f) override { return false; }
167-
168166
public:
169167
fpa_decl_plugin();
170168

@@ -199,6 +197,8 @@ class fpa_decl_plugin : public decl_plugin {
199197

200198
void del(parameter const & p) override;
201199
parameter translate(parameter const & p, decl_plugin & target) override;
200+
201+
bool is_considered_uninterpreted(func_decl * f) override;
202202
};
203203

204204
class fpa_util {
@@ -358,6 +358,8 @@ class fpa_util {
358358

359359
bool contains_floats(ast * a);
360360

361+
bool is_considered_uninterpreted(func_decl* f, unsigned n, expr* const* args);
362+
361363
MATCH_TERNARY(is_fp);
362364
};
363365

0 commit comments

Comments
 (0)