Skip to content

Commit 9ea1cf3

Browse files
na
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent 785c9a1 commit 9ea1cf3

8 files changed

+497
-4
lines changed

src/ast/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ z3_add_component(ast
4444
special_relations_decl_plugin.cpp
4545
static_features.cpp
4646
used_vars.cpp
47+
value_generator.cpp
4748
well_sorted.cpp
4849
COMPONENT_DEPENDENCIES
4950
polynomial

src/ast/value_generator.cpp

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
/*++
2+
Copyright (c) 2020 Microsoft Corporation
3+
4+
Module Name:
5+
6+
value_generatorr.cpp
7+
8+
Abstract:
9+
10+
Generate mostly different values using index as seed.
11+
12+
Author:
13+
14+
Nikolaj Bjorner 2020-04-25
15+
16+
--*/
17+
18+
#include "ast/value_generator.h"
19+
#include "ast/datatype_decl_plugin.h"
20+
#include "ast/array_decl_plugin.h"
21+
#include "ast/arith_decl_plugin.h"
22+
#include "ast/bv_decl_plugin.h"
23+
#include "ast/seq_decl_plugin.h"
24+
#include <cmath>
25+
26+
27+
28+
/*
29+
\brief inverse of the Cantor function.
30+
It converts an unsigned into a pair of unsigned numbers that are not
31+
bigger (and only equal for values 0, 1).
32+
*/
33+
static void inverse_cantor(unsigned z, unsigned& x, unsigned& y) {
34+
unsigned w = ((unsigned)sqrt(8*z + 1) - 1)/2;
35+
unsigned t = (unsigned)(w*w + w)/2;
36+
y = z - t;
37+
x = w - y;
38+
}
39+
40+
static bool is_small_size(sort_size const& sz) {
41+
return sz.is_finite() && sz.size() < (UINT_MAX >> 12);
42+
}
43+
44+
class datatype_value_generator : public value_generator_core {
45+
ast_manager& m;
46+
value_generator& g;
47+
datatype_util dt;
48+
sort_ref_vector m_sorts;
49+
obj_map<sort, expr_ref_vector*> m_values;
50+
obj_map<func_decl, unsigned> m_constr2seen;
51+
random_gen m_rand;
52+
53+
unsigned_vector inf;
54+
void index2vector(unsigned z, func_decl* c, unsigned_vector& v) {
55+
unsigned arity = c->get_arity();
56+
v.resize(arity);
57+
inf.reset();
58+
for (unsigned i = 0; i < arity; ++i) {
59+
sort* s = c->get_domain(i);
60+
sort_size const& sz = s->get_num_elements();
61+
if (is_small_size(sz)) {
62+
v[i] = z % sz.size();
63+
z = z/((unsigned)sz.size());
64+
}
65+
else {
66+
inf.push_back(i);
67+
}
68+
}
69+
// fill in values for large domains
70+
for (unsigned i = 0; i + 1 < inf.size(); ++i) {
71+
inverse_cantor(z, v[inf[i]], z);
72+
}
73+
if (!inf.empty()) {
74+
v[inf.back()] = z;
75+
}
76+
}
77+
78+
bool domain_size_exhausted(unsigned j, func_decl* c) {
79+
unsigned arity = c->get_arity();
80+
uint64_t dsz = 1;
81+
for (unsigned i = 0; i < arity; ++i) {
82+
sort* s = c->get_domain(i);
83+
sort_size const& sz = s->get_num_elements();
84+
if (is_small_size(sz)) {
85+
dsz *= sz.size();
86+
}
87+
else {
88+
return false;
89+
}
90+
if (dsz > j) {
91+
return false;
92+
}
93+
}
94+
return j >= dsz;
95+
}
96+
97+
98+
public:
99+
datatype_value_generator(value_generator& g, ast_manager& m):
100+
m(m), g(g), dt(m), m_sorts(m) {}
101+
102+
~datatype_value_generator() {
103+
for (auto& kv : m_values) dealloc(kv.m_value);
104+
}
105+
106+
family_id get_fid() const override {
107+
return dt.get_family_id();
108+
}
109+
110+
/*
111+
In the off chance that a recursive datatype constructor is left recursive and has no base case on its own
112+
we iterate over constructors in a random order to make sure to hit the base cases eventually.
113+
In such cases m_constr2seen might not get updated accurately and we admit repetitions.
114+
115+
*/
116+
unsigned_vector indices;
117+
expr_ref get_value(sort* s, unsigned index) override {
118+
expr_ref_vector* vp = nullptr;
119+
if (!m_values.find(s, vp)) {
120+
vp = alloc(expr_ref_vector, m);
121+
for (auto* c : *dt.get_datatype_constructors(s)) {
122+
if (c->get_arity() == 0)
123+
vp->push_back(m.mk_const(c));
124+
}
125+
m_values.insert(s, vp);
126+
m_sorts.push_back(s);
127+
}
128+
auto& v = *vp;
129+
expr_ref_vector args(m);
130+
bool some_valid = true;
131+
while (v.size() <= index && some_valid) {
132+
some_valid = false;
133+
auto const& decls = *dt.get_datatype_constructors(s);
134+
int start = m_rand();
135+
for (unsigned i = 0; i < decls.size(); ++i) {
136+
func_decl* c = decls[(i + start) % decls.size()];
137+
unsigned arity = c->get_arity();
138+
if (arity == 0)
139+
continue;
140+
args.resize(c->get_arity());
141+
unsigned j = 0;
142+
m_constr2seen.find(c, j);
143+
if (domain_size_exhausted(j, c))
144+
continue;
145+
m_constr2seen.insert(c, j + 1);
146+
index2vector(j, c, indices);
147+
bool valid = true;
148+
for (unsigned i = 0; valid && i < args.size(); ++i) {
149+
args[i] = g.get_value(c->get_domain(i), indices[i]);
150+
valid &= args.get(i) != nullptr;
151+
}
152+
if (valid) {
153+
v.push_back(m.mk_app(c, args));
154+
some_valid = true;
155+
}
156+
}
157+
}
158+
return expr_ref(v.get(index, nullptr), m);
159+
}
160+
};
161+
162+
163+
class arith_value_generator : public value_generator_core {
164+
ast_manager& m;
165+
arith_util a;
166+
int u2i(unsigned u) {
167+
if (0 == (u % 2))
168+
return u/2;
169+
else
170+
return -(int)((u+1)/2);
171+
}
172+
173+
void calkin_wilf(unsigned i, unsigned& x, unsigned& y) {
174+
while (i > 1) {
175+
if (i % 2 == 0) {
176+
x += y;
177+
}
178+
else {
179+
y += x;
180+
}
181+
i /= 2;
182+
}
183+
}
184+
185+
public:
186+
arith_value_generator(ast_manager& m): m(m), a(m) {}
187+
188+
family_id get_fid() const override {
189+
return a.get_family_id();
190+
}
191+
192+
expr_ref get_value(sort* s, unsigned index) override {
193+
if (a.is_int(s)) {
194+
return expr_ref(a.mk_int(u2i(index)), m);
195+
}
196+
if (index == 0)
197+
return expr_ref(a.mk_real(rational(0)), m);
198+
unsigned x = 1, y = 1;
199+
calkin_wilf((index/2) + 1, x, y);
200+
if ((index % 2) == 0) x = -(int)x;
201+
return expr_ref(a.mk_real(rational(x, y)), m);
202+
}
203+
};
204+
205+
class seq_value_generator : public value_generator_core {
206+
ast_manager& m;
207+
value_generator& g;
208+
seq_util seq;
209+
public:
210+
seq_value_generator(value_generator& g, ast_manager& m): g(g), m(m), seq(m) {}
211+
212+
family_id get_fid() const override {
213+
return seq.get_family_id();
214+
}
215+
216+
expr_ref get_value(sort* s, unsigned index) override {
217+
sort* elem_sort = nullptr;
218+
if (!seq.is_seq(s, elem_sort)) {
219+
return expr_ref(m.mk_fresh_const("re", s), m);
220+
}
221+
if (index == 0) {
222+
return expr_ref(seq.str.mk_empty(s), m);
223+
}
224+
--index;
225+
sort_size const& sz = elem_sort->get_num_elements();
226+
expr_ref_vector es(m);
227+
unsigned idx = 0;
228+
if (is_small_size(sz)) {
229+
// TBD: could also use a Gray-code version
230+
// TBD: could also prefer longer sequences
231+
unsigned esz = (unsigned)sz.size();
232+
index += esz;
233+
do {
234+
idx = index % esz;
235+
expr_ref elem = g.get_value(elem_sort, idx);
236+
es.push_back(seq.str.mk_unit(elem));
237+
index /= esz;
238+
}
239+
while (index >= esz);
240+
}
241+
else {
242+
do {
243+
inverse_cantor(index, idx, index);
244+
expr_ref elem = g.get_value(elem_sort, idx);
245+
es.push_back(seq.str.mk_unit(elem));
246+
}
247+
while (index > 0);
248+
}
249+
return expr_ref(seq.str.mk_concat(es, s), m);
250+
}
251+
};
252+
253+
254+
class array_value_generator : public value_generator_core {
255+
ast_manager& m;
256+
value_generator& g;
257+
array_util a;
258+
public:
259+
array_value_generator(value_generator& g, ast_manager& m): g(g), m(m), a(m) {}
260+
261+
family_id get_fid() const override {
262+
return a.get_family_id();
263+
}
264+
265+
// if both domain and range are finite, this will create repetitions.
266+
// overall, finite domain arrays can be handled separately
267+
// repetitions also happen when the same set of indices are updated twice
268+
269+
expr_ref get_value(sort* s, unsigned index) override {
270+
unsigned arity = get_array_arity(s);
271+
sort* r = get_array_range(s);
272+
sort_size const& sz = r->get_num_elements();
273+
if (sz.is_finite() && sz.size() == 1) {
274+
return expr_ref(a.mk_const_array(s, g.get_value(r, 0)), m);
275+
}
276+
277+
unsigned z = 0;
278+
if (is_small_size(sz)) {
279+
z = index % sz.size();
280+
index = index / (unsigned)sz.size();
281+
}
282+
else {
283+
inverse_cantor(index, z, index);
284+
}
285+
expr_ref result(a.mk_const_array(s, g.get_value(r, z)), m);
286+
unsigned default_index = z;
287+
expr_ref_vector args(m);
288+
unsigned_vector inf;
289+
args.resize(arity+2);
290+
while (index > 0) {
291+
args[0] = result;
292+
for (unsigned i = 0; i < arity; ++i) {
293+
sort* d = get_array_domain(s, i);
294+
sort_size const& dsz = d->get_num_elements();
295+
if (is_small_size(dsz)) {
296+
args[1 + i] = g.get_value(d, index % dsz.size());
297+
index = index / ((unsigned)dsz.size());
298+
}
299+
else {
300+
inf.push_back(i);
301+
}
302+
}
303+
for (unsigned i : inf) {
304+
inverse_cantor(index, z, index);
305+
args[1 + i] = g.get_value(get_array_domain(s, i), z);
306+
}
307+
308+
// ensure z is different from default_index.
309+
if (is_small_size(sz)) {
310+
z = index % (sz.size() - 1);
311+
index = index / (unsigned)sz.size();
312+
}
313+
else {
314+
inverse_cantor(index, z, index);
315+
}
316+
if (z >= default_index) z++;
317+
args[arity+1] = g.get_value(r, z);
318+
result = a.mk_store(args);
319+
}
320+
321+
return result;
322+
}
323+
};
324+
325+
class bv_value_generator : public value_generator_core {
326+
ast_manager& m;
327+
bv_util bv;
328+
public:
329+
bv_value_generator(ast_manager& m): m(m), bv(m) {}
330+
331+
family_id get_fid() const override {
332+
return bv.get_family_id();
333+
}
334+
335+
expr_ref get_value(sort* s, unsigned index) override {
336+
index %= bv.get_bv_size(s);
337+
return expr_ref(bv.mk_numeral(rational(index), s), m);
338+
}
339+
};
340+
341+
class bool_value_generator : public value_generator_core {
342+
ast_manager& m;
343+
public:
344+
bool_value_generator(ast_manager& m): m(m) {}
345+
346+
family_id get_fid() const override {
347+
return m.get_basic_family_id();
348+
}
349+
350+
expr_ref get_value(sort* s, unsigned index) override {
351+
if (!m.is_bool(s))
352+
return expr_ref(m.mk_fresh_const("basic", s), m);
353+
if (index % 2 == 0)
354+
return expr_ref(m.mk_false(), m);
355+
return expr_ref(m.mk_true(), m);
356+
}
357+
};
358+
359+
360+
value_generator::value_generator(ast_manager& m): m(m) {
361+
}
362+
363+
void value_generator::init() {
364+
if (!m_plugins.empty())
365+
return;
366+
add_plugin(alloc(datatype_value_generator, *this, m));
367+
add_plugin(alloc(arith_value_generator, m));
368+
add_plugin(alloc(bv_value_generator, m));
369+
add_plugin(alloc(bool_value_generator, m));
370+
add_plugin(alloc(seq_value_generator, *this, m));
371+
add_plugin(alloc(array_value_generator, *this, m));
372+
// fp_value_generator
373+
// uninterp_sort_value_generator
374+
}
375+
376+
void value_generator::add_plugin(value_generator_core* v) {
377+
m_plugins.reserve(v->get_fid() + 1);
378+
m_plugins.set(v->get_fid(), v);
379+
}
380+
381+
expr_ref value_generator::get_value(sort* s, unsigned index) {
382+
init();
383+
auto fid = s->get_family_id();
384+
auto* p = m_plugins.get(fid, nullptr);
385+
return p ? p->get_value(s, index) : expr_ref(m.mk_fresh_const(s->get_name(), s), m);
386+
}

0 commit comments

Comments
 (0)