Skip to content

Commit 19409a2

Browse files
value sweep
1 parent 38e0968 commit 19409a2

File tree

6 files changed

+271
-0
lines changed

6 files changed

+271
-0
lines changed

src/ast/rewriter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ z3_add_component(rewriter
3333
rewriter.cpp
3434
seq_rewriter.cpp
3535
th_rewriter.cpp
36+
value_sweep.cpp
3637
var_subst.cpp
3738
mk_extract_proc.cpp
3839
COMPONENT_DEPENDENCIES

src/ast/rewriter/value_sweep.cpp

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*++
2+
Copyright (c) 2020 Microsoft Corporation
3+
4+
Module Name:
5+
6+
value_sweep.cpp
7+
8+
Author:
9+
10+
Nikolaj Bjorner 2020-04-25
11+
12+
--*/
13+
14+
#include "ast/for_each_expr.h"
15+
#include "ast/ast_pp.h"
16+
#include "ast/rewriter/value_sweep.h"
17+
18+
value_sweep::value_sweep(ast_manager& m):
19+
m(m),
20+
m_gen(m),
21+
m_rec(m),
22+
m_dt(m),
23+
m_rewrite(m),
24+
m_values(m),
25+
m_args(m),
26+
m_pinned(m),
27+
m_rounds(10),
28+
m_range(20),
29+
m_qhead(0)
30+
{}
31+
32+
void value_sweep::set_value_core(expr* e, expr* v) {
33+
m_values.reserve(e->get_id() + 1);
34+
m_values[e->get_id()] = v;
35+
}
36+
37+
void value_sweep::set_value(expr* e, expr* v) {
38+
set_value_core(e, v);
39+
m_pinned.push_back(e);
40+
}
41+
42+
void value_sweep::reset_values() {
43+
m_values.reset();
44+
m_pinned.reset();
45+
}
46+
47+
expr* value_sweep::get_value(expr* e) const {
48+
if (m_values.size() <= e->get_id())
49+
return nullptr;
50+
return m_values[e->get_id()];
51+
}
52+
53+
void value_sweep::unassign(unsigned sz) {
54+
for (unsigned i = m_queue.size(); i-- > sz; ) {
55+
expr* e = m_queue[i];
56+
m_values[e->get_id()] = nullptr;
57+
}
58+
m_queue.shrink(sz);
59+
m_qhead = sz;
60+
}
61+
62+
bool value_sweep::assign_next_value() {
63+
for (; m_vhead < m_vars.size(); ) {
64+
expr* v = m_vars[m_vhead];
65+
++m_vhead;
66+
if (!get_value(v)) {
67+
unsigned index = m_rand() % m_range;
68+
expr_ref val = m_gen.get_value(m.get_sort(v), index);
69+
set_value_core(v, val);
70+
m_queue.push_back(v);
71+
return true;
72+
}
73+
}
74+
return false;
75+
}
76+
77+
bool value_sweep::is_reducible(expr* e) const {
78+
if (!is_app(e))
79+
return false;
80+
app* a = to_app(e);
81+
return
82+
m_rec.is_defined(a) ||
83+
a->get_family_id() == m_dt.get_family_id() ||
84+
a->get_family_id() == m.get_basic_family_id();
85+
}
86+
87+
bool value_sweep::all_args_have_values(app* p) const {
88+
for (expr* arg : *p) {
89+
if (!get_value(arg))
90+
return false;
91+
}
92+
return true;
93+
}
94+
95+
void value_sweep::propagate_values() {
96+
for (; m_qhead < m_queue.size(); ++m_qhead) {
97+
expr* e = m_queue[m_qhead];
98+
for (app* p : m_parents[e->get_id()]) {
99+
if (get_value(p))
100+
continue;
101+
if (!is_reducible(p))
102+
continue;
103+
if (!all_args_have_values(p))
104+
continue;
105+
m_args.reset();
106+
for (expr* arg : *p)
107+
m_args.push_back(get_value(arg));
108+
expr_ref new_value(m.mk_app(p->get_decl(), m_args), m);
109+
m_rewrite(new_value);
110+
TRACE("value_sweep", tout << "propagate " << mk_pp(p, m) << " " << new_value << "\n";);
111+
set_value_core(p, new_value);
112+
m_queue.push_back(p);
113+
}
114+
}
115+
}
116+
117+
void value_sweep::init(expr_ref_vector const& terms) {
118+
m_parents.reset();
119+
m_queue.reset();
120+
m_vars.reset();
121+
m_qhead = 0;
122+
m_vhead = 0;
123+
for (expr* t : subterms(terms)) {
124+
m_parents.reserve(t->get_id() + 1);
125+
if (get_value(t))
126+
m_queue.push_back(t);
127+
else if (!is_reducible(t))
128+
m_vars.push_back(t);
129+
}
130+
for (expr* t : subterms(terms)) {
131+
if (!is_app(t))
132+
continue;
133+
for (expr* arg : *to_app(t))
134+
m_parents[arg->get_id()].push_back(to_app(t));
135+
}
136+
}
137+
138+
void value_sweep::operator()(expr_ref_vector const& terms,
139+
vector<expr_ref_vector>& values) {
140+
141+
unsigned qhead0 = m_queue.size();
142+
init(terms);
143+
propagate_values();
144+
unsigned qhead = m_queue.size();
145+
for (unsigned i = 0; i < m_rounds; ++i) {
146+
m_vhead = 0;
147+
while (assign_next_value()) {
148+
propagate_values();
149+
}
150+
expr_ref_vector vec(m);
151+
for (expr* t : terms) {
152+
vec.push_back(get_value(t));
153+
}
154+
values.push_back(vec);
155+
unassign(qhead);
156+
}
157+
unassign(qhead0);
158+
}

src/ast/rewriter/value_sweep.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*++
2+
Copyright (c) 2020 Microsoft Corporation
3+
4+
Module Name:
5+
6+
value_sweep.h
7+
8+
Abstract:
9+
10+
Evaluate terms using different random initial assignments.
11+
Return the assignments.
12+
13+
Author:
14+
15+
Nikolaj Bjorner 2020-04-27
16+
17+
--*/
18+
19+
#pragma once
20+
21+
#include "ast/value_generator.h"
22+
#include "ast/recfun_decl_plugin.h"
23+
#include "ast/datatype_decl_plugin.h"
24+
#include "ast/rewriter/th_rewriter.h"
25+
26+
class value_sweep {
27+
typedef vector<ptr_vector<app>> parents_t;
28+
29+
ast_manager& m;
30+
value_generator m_gen;
31+
recfun::util m_rec;
32+
datatype::util m_dt;
33+
th_rewriter m_rewrite;
34+
expr_ref_vector m_values;
35+
expr_ref_vector m_args;
36+
expr_ref_vector m_pinned;
37+
unsigned m_rounds;
38+
unsigned m_range;
39+
random_gen m_rand;
40+
41+
parents_t m_parents;
42+
ptr_vector<expr> m_queue;
43+
ptr_vector<expr> m_vars;
44+
unsigned m_qhead;
45+
unsigned m_vhead;
46+
47+
void init(expr_ref_vector const& terms);
48+
49+
void set_value_core(expr* e, expr* v);
50+
51+
expr* get_value(expr* e) const;
52+
53+
void unassign(unsigned qhead);
54+
55+
void propagate_values();
56+
57+
bool assign_next_value();
58+
59+
bool is_reducible(expr* e) const;
60+
61+
bool all_args_have_values(app* p) const;
62+
63+
64+
public:
65+
value_sweep(ast_manager& m);
66+
void set_rounds(unsigned r) { m_rounds = r; }
67+
void set_range(unsigned r) { m_range = r; }
68+
void set_value(expr* e, expr* v);
69+
void reset_values();
70+
71+
void operator()(expr_ref_vector const& terms,
72+
vector<expr_ref_vector>& values);
73+
};

src/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ add_executable(test-z3
123123
uint_set.cpp
124124
upolynomial.cpp
125125
value_generator.cpp
126+
value_sweep.cpp
126127
var_subst.cpp
127128
vector.cpp
128129
lp/lp.cpp

src/test/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ int main(int argc, char ** argv) {
218218
TST(ext_numeral);
219219
TST(interval);
220220
TST(value_generator);
221+
TST(value_sweep);
221222
TST(vector);
222223
TST(f2n);
223224
TST(hwf);

src/test/value_sweep.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "ast/rewriter/value_sweep.h"
2+
#include "ast/reg_decl_plugins.h"
3+
#include "ast/ast_pp.h"
4+
#include "ast/seq_decl_plugin.h"
5+
#include "ast/array_decl_plugin.h"
6+
7+
void tst_value_sweep() {
8+
ast_manager m;
9+
reg_decl_plugins(m);
10+
datatype_util dt(m);
11+
arith_util a(m);
12+
array_util ar(m);
13+
seq_util seq(m);
14+
sort_ref int_sort(a.mk_int(), m);
15+
func_decl_ref cons(m), is_cons(m), head(m), tail(m), nil(m), is_nil(m);
16+
17+
sort_ref ilist = dt.mk_list_datatype(int_sort, symbol("ilist"),
18+
cons, is_cons, head, tail, nil, is_nil);
19+
20+
expr_ref n(m.mk_const("n", int_sort), m);
21+
expr_ref v1(m.mk_const("v1", ilist), m);
22+
expr_ref v2(m.mk_const("v2", ilist), m);
23+
std::cout << cons << "\n";
24+
expr_ref v3(m.mk_app(cons.get(), n, v1), m);
25+
expr_ref_vector terms(m);
26+
terms.push_back(v1).push_back(v2).push_back(v3);
27+
vector<expr_ref_vector> values;
28+
value_sweep ws(m);
29+
ws.set_range(30);
30+
ws(terms, values);
31+
for (auto const& vec : values) {
32+
for (expr* v : vec) {
33+
std::cout << mk_pp(v, m) << "\n";
34+
}
35+
std::cout << "\n";
36+
}
37+
}

0 commit comments

Comments
 (0)