|
| 1 | +#include "smt/value_generator.h" |
| 2 | +#include <math> |
| 3 | + |
| 4 | + |
| 5 | +class datatype_value_generator : public value_generator_core { |
| 6 | + ast_manager& m; |
| 7 | + value_generator& g; |
| 8 | + datatype_util dt; |
| 9 | + sort_ref_vector m_sorts; |
| 10 | + obj_map<sort, expr_ref_vector*> m_values; |
| 11 | + obj_map<func_decl, unsigned> m_constr2seen; |
| 12 | + |
| 13 | + /* |
| 14 | + \brief inverse of the Cantor function. |
| 15 | + It converts an unsigned into a pair of unsigned numbers that are not |
| 16 | + bigger (and only equal for values 0, 1). |
| 17 | + */ |
| 18 | + void inverse_cantor(unsigned z, unsigned& x, unsigned& y) { |
| 19 | + unsigned w = (sqrt(8*z + 1) - 1)/2; |
| 20 | + unsigned t = (w*w + 2)/2; |
| 21 | + y = z - t; |
| 22 | + x = w - y; |
| 23 | + } |
| 24 | + |
| 25 | + unsigned_vector inf; |
| 26 | + void index2vector(unsigned z, func_decl* c, unsigned_vector& v) { |
| 27 | + unsigned arity = c->get_arity(); |
| 28 | + v.resize(arity); |
| 29 | + inf.reset(); |
| 30 | + for (unsigned i = 0; i < arity; ++i) { |
| 31 | + sort* s = c->get_domain(i); |
| 32 | + sort_size const& sz = s->get_num_elements(); |
| 33 | + if (sz.is_finite() && sz.size() < (UINT_MAX >> 12)) { |
| 34 | + v[i] = z % sz.size(); |
| 35 | + z /= sz.size(); |
| 36 | + } |
| 37 | + else { |
| 38 | + inf.push_back(i); |
| 39 | + } |
| 40 | + } |
| 41 | + // fill in values for large domains |
| 42 | + for (unsigned i = 0; i + 1 < inf.size(); ++i) { |
| 43 | + inverse_cantor(z, v[inf[i]], z); |
| 44 | + } |
| 45 | + if (!inf.empty()) { |
| 46 | + v[inf.back()] = z; |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +public: |
| 51 | + datatype_value_generator(value_generator& g, ast_manager& m): |
| 52 | + m(m), g(g), dt(m), m_values(m) {} |
| 53 | + |
| 54 | + ~datatype_value_generator() { |
| 55 | + for (auto& kv : m_values) dealloc(kv.m_value); |
| 56 | + } |
| 57 | + |
| 58 | + family_id get_fid() const override { |
| 59 | + return dt.get_family_id(); |
| 60 | + } |
| 61 | + |
| 62 | + expr* get_value(sort* s, unsigned index) override { |
| 63 | + expr_ref_vector* vp = nullptr; |
| 64 | + if (!m_values.contains(s, vp)) { |
| 65 | + vp = allocate(expr_ref_vector, m); |
| 66 | + for (auto* c : *dt.get_datatype_constructors(s)) { |
| 67 | + if (c->get_arity() == 0) |
| 68 | + vp->push_back(m.mk_app(c)); |
| 69 | + } |
| 70 | + m_values.insert(s, vp); |
| 71 | + } |
| 72 | + auto& v = *vp; |
| 73 | + expr_ref_vector args(m); |
| 74 | + bool some_valid = true; |
| 75 | + while (v.size() <= index && some_valid) { |
| 76 | + some_valid = false; |
| 77 | + for (auto* c : *dt.get_datatype_constructors(s)) { |
| 78 | + unsigned arity = c->get_arity(); |
| 79 | + if (arity == 0) |
| 80 | + continue; |
| 81 | + args.resize(c->get_arity()); |
| 82 | + unsigned j = 0; |
| 83 | + m_constr2seen.find(c, j); |
| 84 | + m_constr2seen.insert(c, j+1); |
| 85 | + if (beyond_domain_size(j, c)) |
| 86 | + continue; |
| 87 | + index2vector(j, c, indices); |
| 88 | + bool valid = true; |
| 89 | + // still does not ensure non-termination when |
| 90 | + // 0 is used on a left-recursive datatype constructor |
| 91 | + for (unsigned i = 0; valid && i < args.size(); ++i) { |
| 92 | + args[i] = g.get_value(c->get_domain(i), indices[i]); |
| 93 | + valid &= args.get(i) != nullptr; |
| 94 | + } |
| 95 | + if (valid) { |
| 96 | + v.push_back(m.mk_app(c, args)); |
| 97 | + some_valid = true; |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + return v.get(index, nullptr); |
| 102 | + } |
| 103 | +}; |
| 104 | + |
| 105 | + |
| 106 | +class arith_value_generator : public value_generator_core { |
| 107 | + ast_manager& m; |
| 108 | + arith_util a; |
| 109 | + int u2i(unsigned u) { |
| 110 | + if (0 == (u % 2)) |
| 111 | + return u/2; |
| 112 | + else |
| 113 | + return -((u+1)/2); |
| 114 | + } |
| 115 | +public: |
| 116 | + arith_value_generator(ast_manager& m): m(m), a(m) {} |
| 117 | + |
| 118 | + family_id get_fid() const override { |
| 119 | + return a.get_family_id(); |
| 120 | + } |
| 121 | + |
| 122 | + expr* get_value(sort* s, unsigned index) override { |
| 123 | + if (a.is_int(s)) { |
| 124 | + return a.mk_int(u2i(index)); |
| 125 | + } |
| 126 | + if (index == 0) |
| 127 | + return a.mk_real(rational(0)); |
| 128 | + unsigned x, y; |
| 129 | + // still imperfect as y could divide x |
| 130 | + inverse_cantor(index/2, x, y); |
| 131 | + x++; |
| 132 | + y++; |
| 133 | + if (index % 2 == 0) x = -x; |
| 134 | + return a.mk_real(rational(x, y)); |
| 135 | + } |
| 136 | +}; |
| 137 | + |
| 138 | +class bv_value_generator : public value_generator_core { |
| 139 | + ast_manager& m; |
| 140 | + bv_util bv; |
| 141 | +public: |
| 142 | + bv_value_generator(ast_manager& m): m(m), bv(m) {} |
| 143 | + |
| 144 | + family_id get_fid() const override { |
| 145 | + return bv.get_family_id(); |
| 146 | + } |
| 147 | + |
| 148 | + expr* get_value(sort* s, unsigned index) override { |
| 149 | + unsigned sz = 0; |
| 150 | + bv.get_bv_size(s, sz); |
| 151 | + if (sz < 30 && index >= (1 << sz)) |
| 152 | + return nullptr; |
| 153 | + return bv.mk_numeral(index, s); |
| 154 | + } |
| 155 | +}; |
| 156 | + |
| 157 | +class bool_value_generator : public value_generator_core { |
| 158 | + ast_manager& m; |
| 159 | +public: |
| 160 | + bool_value_generator(ast_manager& m): m(m) {} |
| 161 | + |
| 162 | + family_id get_fid() const override { |
| 163 | + return m.get_family_id(); |
| 164 | + } |
| 165 | + |
| 166 | + expr* get_value(sort* s, unsigned index) override { |
| 167 | + if (!m.is_bool(s)) |
| 168 | + return nullptr; |
| 169 | + if (index == 0) |
| 170 | + return m.mk_false(); |
| 171 | + if (index == 1) |
| 172 | + return m.mk_true(); |
| 173 | + return nullptr; |
| 174 | + } |
| 175 | +}; |
| 176 | + |
| 177 | + |
| 178 | +value_generator::value_generator(ast_manager& m): m(m) { |
| 179 | +} |
| 180 | + |
| 181 | +void value_generator::init() { |
| 182 | + if (!m_plugins.empty()) |
| 183 | + return; |
| 184 | + add_plugin(alloc(datatype_value_generator, *this, m)); |
| 185 | + add_plugin(alloc(arith_value_generator, m)); |
| 186 | + add_plugin(alloc(bv_value_generator, m)); |
| 187 | + add_plugin(alloc(bool_value_generator, m)); |
| 188 | + // seq_value_generator |
| 189 | + // fp_value_generator |
| 190 | + // array_value_generator |
| 191 | + // uninterp_sort_value_generator |
| 192 | +} |
| 193 | + |
| 194 | +void value_generator::add_plugin(value_generator_core* v) { |
| 195 | + m_plugins.reserve(v->get_fid() + 1); |
| 196 | + m_plugins.set(v->get_fid(), v); |
| 197 | +} |
| 198 | + |
| 199 | +expr* value_generator::get_value(sort* s, unsigned index) { |
| 200 | + init(); |
| 201 | + famiily_id fid = s->get_family_id(); |
| 202 | + auto* p = m_plugins.get(fid, nullptr); |
| 203 | + return p ? p->get_value(s, index) : nullptr; |
| 204 | +} |
0 commit comments