Skip to content

Commit d32a199

Browse files
Restore stable quantifier benchmark behavior
Add an opt-in legacy nested-binder pattern inference mode and restore the previous hash combiner to avoid order-sensitive solver regressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 637d396 commit d32a199

6 files changed

Lines changed: 97 additions & 12 deletions

File tree

src/ast/pattern/pattern_inference.cpp

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ inline void pattern_inference_cfg::collect::save(expr * n, unsigned delta, info
181181
}
182182

183183
void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
184+
if (m_owner.m_params.m_pi_legacy_nested_binders) {
185+
save_candidate_legacy(n, delta);
186+
return;
187+
}
184188
switch (n->get_kind()) {
185189
case AST_VAR: {
186190
uint_set free_vars, bound_vars;
@@ -189,7 +193,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
189193
free_vars.insert(idx - delta);
190194
else if (idx < delta)
191195
bound_vars.insert(idx);
192-
info * i = alloc(info, free_vars, bound_vars, 1);
196+
info * i = alloc(info, m, n, free_vars, bound_vars, 1);
193197
save(n, delta, i);
194198
return;
195199
}
@@ -201,7 +205,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
201205
}
202206

203207
if (c->get_num_args() == 0) {
204-
save(n, delta, alloc(info, uint_set(), uint_set(), 1));
208+
save(n, delta, alloc(info, m, n, uint_set(), uint_set(), 1));
205209
return;
206210
}
207211

@@ -219,7 +223,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
219223
size += child_info->m_size;
220224
}
221225

222-
save(n, delta, alloc(info, free_vars, bound_vars, size));
226+
save(n, delta, alloc(info, m, n, free_vars, bound_vars, size));
223227
// Remark: arithmetic patterns are only used if they are nested inside other terms.
224228
// That is, we never consider x + 1 as pattern. On the other hand, f(x+1) can be a pattern
225229
// if arithmetic is not in the forbidden list.
@@ -251,7 +255,82 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
251255
if (b >= num_decls)
252256
bound_vars.insert(b - num_decls);
253257

254-
save(n, delta, alloc(info, body_info->m_free_vars, bound_vars, body_info->m_size + 1));
258+
save(n, delta, alloc(info, m, n, body_info->m_free_vars, bound_vars, body_info->m_size + 1));
259+
return;
260+
}
261+
default:
262+
save(n, delta, nullptr);
263+
return;
264+
}
265+
}
266+
267+
void pattern_inference_cfg::collect::save_candidate_legacy(expr * n, unsigned delta) {
268+
switch (n->get_kind()) {
269+
case AST_VAR: {
270+
unsigned idx = to_var(n)->get_idx();
271+
if (idx < delta) {
272+
save(n, delta, nullptr);
273+
return;
274+
}
275+
idx -= delta;
276+
uint_set free_vars;
277+
if (idx < m_num_bindings)
278+
free_vars.insert(idx);
279+
expr * new_node = delta == 0 ? n : m.mk_var(idx, to_var(n)->get_sort());
280+
save(n, delta, alloc(info, m, new_node, free_vars, 1));
281+
return;
282+
}
283+
case AST_APP: {
284+
app * c = to_app(n);
285+
if (m_owner.is_forbidden(c)) {
286+
save(n, delta, nullptr);
287+
return;
288+
}
289+
if (c->get_num_args() == 0) {
290+
save(n, delta, alloc(info, m, n, uint_set(), 1));
291+
return;
292+
}
293+
ptr_buffer<expr> args;
294+
bool changed = false;
295+
uint_set free_vars;
296+
unsigned size = 1;
297+
for (expr * child : *c) {
298+
info * child_info = nullptr;
299+
VERIFY(m_cache.find(entry(child, delta), child_info));
300+
if (!child_info) {
301+
save(n, delta, nullptr);
302+
return;
303+
}
304+
args.push_back(child_info->m_node);
305+
free_vars |= child_info->m_free_vars;
306+
size += child_info->m_size;
307+
changed |= child != child_info->m_node;
308+
}
309+
app * new_node = changed ? m.mk_app(c->get_decl(), args.size(), args.data()) : c;
310+
save(n, delta, alloc(info, m, new_node, free_vars, size));
311+
family_id fid = c->get_family_id();
312+
decl_kind k = c->get_decl_kind();
313+
if (!free_vars.empty() &&
314+
(fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only &&
315+
(k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL))))
316+
m_owner.add_candidate(new_node, free_vars, size);
317+
return;
318+
}
319+
case AST_QUANTIFIER: {
320+
quantifier * q = to_quantifier(n);
321+
unsigned num_decls = q->get_num_decls();
322+
info * body_info = nullptr;
323+
m_cache.find(entry(q->get_expr(), delta + num_decls), body_info);
324+
if (!body_info) {
325+
save(n, delta, nullptr);
326+
return;
327+
}
328+
expr_ref new_body(m);
329+
var_shifter shift(m);
330+
shift(body_info->m_node, num_decls, new_body);
331+
quantifier_ref new_q(m);
332+
new_q = new_body == q->get_expr() ? q : m.update_quantifier(q, new_body);
333+
save(n, delta, alloc(info, m, new_q, body_info->m_free_vars, body_info->m_size + 1));
255334
return;
256335
}
257336
default:

src/ast/pattern/pattern_inference.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,13 @@ class pattern_inference_cfg : public default_rewriter_cfg {
125125
};
126126

127127
struct info {
128+
expr_ref m_node;
128129
uint_set m_free_vars, m_bound_vars;
129130
unsigned m_size;
130-
info(uint_set const & fvars, uint_set const& bvars, unsigned sz):
131-
m_free_vars(fvars), m_bound_vars(bvars), m_size(sz) {}
131+
info(ast_manager& m, expr * n, uint_set const& fvars, uint_set const& bvars, unsigned sz):
132+
m_node(n, m), m_free_vars(fvars), m_bound_vars(bvars), m_size(sz) {}
133+
info(ast_manager& m, expr * n, uint_set const& fvars, unsigned sz):
134+
m_node(n, m), m_free_vars(fvars), m_size(sz) {}
132135
};
133136

134137
ast_manager & m;
@@ -144,6 +147,7 @@ class pattern_inference_cfg : public default_rewriter_cfg {
144147
bool visit_children(expr * n, unsigned delta);
145148
void save(expr * n, unsigned delta, info * i);
146149
void save_candidate(expr * n, unsigned delta);
150+
void save_candidate_legacy(expr * n, unsigned delta);
147151
void reset();
148152
public:
149153
collect(ast_manager & m, pattern_inference_cfg & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
@@ -253,5 +257,3 @@ class pattern_inference_rw : public rewriter_tpl<pattern_inference_cfg> {
253257
public:
254258
pattern_inference_rw(ast_manager& m, pattern_inference_params const & params);
255259
};
256-
257-

src/params/pattern_inference_params.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void pattern_inference_params::updt_params(params_ref const & _p) {
2727
m_pi_decompose_patterns = p.decompose_patterns();
2828
m_pi_arith = static_cast<arith_pattern_inference_kind>(p.arith());
2929
m_pi_use_database = p.use_database();
30+
m_pi_legacy_nested_binders = p.legacy_nested_binders();
3031
m_pi_arith_weight = p.arith_weight();
3132
m_pi_non_nested_arith_weight = p.non_nested_arith_weight();
3233
m_pi_pull_quantifiers = p.pull_quantifiers();
@@ -43,6 +44,7 @@ void pattern_inference_params::display(std::ostream & out) const {
4344
DISPLAY_PARAM(m_pi_decompose_patterns);
4445
DISPLAY_PARAM(m_pi_arith);
4546
DISPLAY_PARAM(m_pi_use_database);
47+
DISPLAY_PARAM(m_pi_legacy_nested_binders);
4648
DISPLAY_PARAM(m_pi_arith_weight);
4749
DISPLAY_PARAM(m_pi_non_nested_arith_weight);
4850
DISPLAY_PARAM(m_pi_pull_quantifiers);

src/params/pattern_inference_params.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct pattern_inference_params {
3333
bool m_pi_decompose_patterns;
3434
arith_pattern_inference_kind m_pi_arith;
3535
bool m_pi_use_database;
36+
bool m_pi_legacy_nested_binders;
3637
unsigned m_pi_arith_weight;
3738
unsigned m_pi_non_nested_arith_weight;
3839
bool m_pi_pull_quantifiers;
@@ -48,5 +49,3 @@ struct pattern_inference_params {
4849

4950
void display(std::ostream & out) const;
5051
};
51-
52-

src/params/pattern_inference_params_helper.pyg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ def_module_params(class_name='pattern_inference_params_helper',
88
('arith', UINT, 1, '0 - do not infer patterns with arithmetic terms, 1 - use patterns with arithmetic terms if there is no other pattern, 2 - always use patterns with arithmetic terms'),
99
('use_database', BOOL, False, 'use pattern database'),
1010
('enabled', BOOL, True, 'enable a heuristic to infer patterns, when they are not provided'),
11+
('legacy_nested_binders', BOOL, False, 'use legacy pattern inference behavior below nested binders'),
1112
('arith_weight', UINT, 5, 'default weight for quantifiers where the only available pattern has nested arithmetic terms'),
1213
('non_nested_arith_weight', UINT, 10, 'default weight for quantifiers where the only available pattern has non nested arithmetic terms'),
1314
('pull_quantifiers', BOOL, True, 'pull nested quantifiers, if no pattern was found'),

src/util/hash.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ static inline unsigned hash_ull(unsigned long long a) {
5757
}
5858

5959
static inline unsigned combine_hash(unsigned h1, unsigned h2) {
60-
h1 ^= h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2);
61-
return hash_u(h1);
60+
h2 -= h1; h2 ^= (h1 << 8);
61+
h1 -= h2; h2 ^= (h1 << 16);
62+
h2 -= h1; h2 ^= (h1 << 10);
63+
return h2;
6264
}
6365

6466
static inline unsigned hash_u_u(unsigned a, unsigned b) {

0 commit comments

Comments
 (0)