Skip to content

Commit f919380

Browse files
add recfun rewriting, remove quantifier based recfun
1 parent 7f1b147 commit f919380

13 files changed

+94
-143
lines changed

src/api/api_quant.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,11 @@ extern "C" {
7272
expr * const* ps = reinterpret_cast<expr * const*>(patterns);
7373
expr * const* no_ps = reinterpret_cast<expr * const*>(no_patterns);
7474
symbol qid = to_symbol(quantifier_id);
75-
bool is_rec = mk_c(c)->m().rec_fun_qid() == qid;
76-
if (!is_rec) {
77-
pattern_validator v(mk_c(c)->m());
78-
for (unsigned i = 0; i < num_patterns; i++) {
79-
if (!v(num_decls, ps[i], 0, 0)) {
80-
SET_ERROR_CODE(Z3_INVALID_PATTERN, nullptr);
81-
return nullptr;
82-
}
75+
pattern_validator v(mk_c(c)->m());
76+
for (unsigned i = 0; i < num_patterns; i++) {
77+
if (!v(num_decls, ps[i], 0, 0)) {
78+
SET_ERROR_CODE(Z3_INVALID_PATTERN, nullptr);
79+
return nullptr;
8380
}
8481
}
8582
sort* const* ts = reinterpret_cast<sort * const*>(sorts);

src/ast/ast.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,7 +1379,6 @@ ast_manager::ast_manager(proof_gen_mode m, char const * trace_file, bool is_form
13791379
m_proof_mode(m),
13801380
m_trace_stream(nullptr),
13811381
m_trace_stream_owner(false),
1382-
m_rec_fun(":rec-fun"),
13831382
m_lambda_def(":lambda-def") {
13841383

13851384
if (trace_file) {
@@ -1403,7 +1402,6 @@ ast_manager::ast_manager(proof_gen_mode m, std::fstream * trace_stream, bool is_
14031402
m_proof_mode(m),
14041403
m_trace_stream(trace_stream),
14051404
m_trace_stream_owner(false),
1406-
m_rec_fun(":rec-fun"),
14071405
m_lambda_def(":lambda-def") {
14081406

14091407
if (!is_format_manager)
@@ -1421,7 +1419,6 @@ ast_manager::ast_manager(ast_manager const & src, bool disable_proofs):
14211419
m_proof_mode(disable_proofs ? PGM_DISABLED : src.m_proof_mode),
14221420
m_trace_stream(src.m_trace_stream),
14231421
m_trace_stream_owner(false),
1424-
m_rec_fun(":rec-fun"),
14251422
m_lambda_def(":lambda-def") {
14261423
SASSERT(!src.is_format_manager());
14271424
m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true);
@@ -1756,13 +1753,6 @@ quantifier* ast_manager::is_lambda_def(func_decl* f) {
17561753
return nullptr;
17571754
}
17581755

1759-
1760-
func_decl* ast_manager::get_rec_fun_decl(quantifier* q) const {
1761-
SASSERT(is_rec_fun_def(q));
1762-
return to_app(to_app(q->get_pattern(0))->get_arg(0))->get_decl();
1763-
}
1764-
1765-
17661756
void ast_manager::register_plugin(family_id id, decl_plugin * plugin) {
17671757
SASSERT(m_plugins.get(id, 0) == 0);
17681758
m_plugins.setx(id, plugin, 0);

src/ast/ast.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,6 @@ class ast_manager {
15531553
bool slow_not_contains(ast const * n);
15541554
#endif
15551555
ast_manager * m_format_manager; // hack for isolating format objects in a different manager.
1556-
symbol m_rec_fun;
15571556
symbol m_lambda_def;
15581557

15591558
void init();
@@ -1666,13 +1665,10 @@ class ast_manager {
16661665

16671666
bool contains(ast * a) const { return m_ast_table.contains(a); }
16681667

1669-
bool is_rec_fun_def(quantifier* q) const { return q->get_qid() == m_rec_fun; }
16701668
bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; }
16711669
void add_lambda_def(func_decl* f, quantifier* q);
16721670
quantifier* is_lambda_def(func_decl* f);
1673-
func_decl* get_rec_fun_decl(quantifier* q) const;
16741671

1675-
symbol const& rec_fun_qid() const { return m_rec_fun; }
16761672

16771673
symbol const& lambda_def_qid() const { return m_lambda_def; }
16781674

src/ast/recfun_decl_plugin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ namespace recfun {
220220
~util();
221221

222222
ast_manager & m() { return m_manager; }
223+
family_id get_family_id() const { return m_fid; }
223224
decl::plugin& get_plugin() { return *m_plugin; }
224225

225226
bool is_case_pred(expr * e) const { return is_app_of(e, m_fid, OP_FUN_CASE_PRED); }

src/ast/rewriter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ z3_add_component(rewriter
2929
pb2bv_rewriter.cpp
3030
push_app_ite.cpp
3131
quant_hoist.cpp
32+
recfun_rewriter.cpp
3233
rewriter.cpp
3334
seq_rewriter.cpp
3435
th_rewriter.cpp

src/ast/rewriter/recfun_rewriter.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*++
2+
Copyright (c) 2018 Microsoft Corporation
3+
4+
Module Name:
5+
6+
recfun_rewriter.cpp
7+
8+
Abstract:
9+
10+
Rewriter recursive function applications to values
11+
12+
Author:
13+
14+
Nikolaj Bjorner (nbjorner) 2020-04-26
15+
16+
17+
--*/
18+
19+
20+
#include "ast/rewriter/recfun_rewriter.h"
21+
#include "ast/rewriter/var_subst.h"
22+
23+
br_status recfun_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
24+
if (m_rec.is_defined(f)) {
25+
for (unsigned i = 0; i < num_args; ++i) {
26+
if (!m.is_value(args[i]))
27+
return BR_FAILED;
28+
}
29+
recfun::def const& d = m_rec.get_def(f);
30+
var_subst sub(m);
31+
result = sub(d.get_rhs(), num_args, args);
32+
return BR_REWRITE_FULL;
33+
}
34+
else {
35+
return BR_FAILED;
36+
}
37+
}
38+
39+

src/ast/rewriter/recfun_rewriter.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*++
2+
Copyright (c) 2018 Microsoft Corporation
3+
4+
Module Name:
5+
6+
recfun_rewriter.h
7+
8+
Abstract:
9+
10+
Rewriter recursive function applications to values
11+
12+
Author:
13+
14+
Nikolaj Bjorner (nbjorner) 2020-04-26
15+
16+
17+
--*/
18+
19+
#pragma once
20+
21+
#include "ast/recfun_decl_plugin.h"
22+
#include "ast/rewriter/rewriter.h"
23+
24+
class recfun_rewriter {
25+
ast_manager& m;
26+
recfun::util m_rec;
27+
public:
28+
recfun_rewriter(ast_manager& m): m(m), m_rec(m) {}
29+
~recfun_rewriter() {}
30+
31+
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
32+
33+
family_id get_fid() const { return m_rec.get_family_id(); }
34+
35+
};
36+

src/ast/rewriter/th_rewriter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Module Name:
2626
#include "ast/rewriter/fpa_rewriter.h"
2727
#include "ast/rewriter/dl_rewriter.h"
2828
#include "ast/rewriter/pb_rewriter.h"
29+
#include "ast/rewriter/recfun_rewriter.h"
2930
#include "ast/rewriter/seq_rewriter.h"
3031
#include "ast/rewriter/rewriter_def.h"
3132
#include "ast/rewriter/var_subst.h"
@@ -46,6 +47,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
4647
dl_rewriter m_dl_rw;
4748
pb_rewriter m_pb_rw;
4849
seq_rewriter m_seq_rw;
50+
recfun_rewriter m_rec_rw;
4951
arith_util m_a_util;
5052
bv_util m_bv_util;
5153
unsigned long long m_max_memory; // in bytes
@@ -219,6 +221,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
219221
return m_pb_rw.mk_app_core(f, num, args, result);
220222
if (fid == m_seq_rw.get_fid())
221223
return m_seq_rw.mk_app_core(f, num, args, result);
224+
if (fid == m_rec_rw.get_fid())
225+
return m_rec_rw.mk_app_core(f, num, args, result);
222226
return BR_FAILED;
223227
}
224228

@@ -747,6 +751,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
747751
m_dl_rw(m),
748752
m_pb_rw(m),
749753
m_seq_rw(m),
754+
m_rec_rw(m),
750755
m_a_util(m),
751756
m_bv_util(m),
752757
m_used_dependencies(m),

src/smt/smt_context.cpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4507,32 +4507,6 @@ namespace smt {
45074507

45084508
void context::add_rec_funs_to_model() {
45094509
if (!m_model) return;
4510-
for (unsigned i = 0; !get_cancel_flag() && i < m_asserted_formulas.get_num_formulas(); ++i) {
4511-
expr* e = m_asserted_formulas.get_formula(i);
4512-
if (is_quantifier(e)) {
4513-
quantifier* q = to_quantifier(e);
4514-
if (!m.is_rec_fun_def(q)) continue;
4515-
TRACE("context", tout << mk_pp(e, m) << "\n";);
4516-
SASSERT(q->get_num_patterns() == 2);
4517-
expr* fn = to_app(q->get_pattern(0))->get_arg(0);
4518-
expr* body = to_app(q->get_pattern(1))->get_arg(0);
4519-
SASSERT(is_app(fn));
4520-
// reverse argument order so that variable 0 starts at the beginning.
4521-
expr_ref_vector subst(m);
4522-
unsigned idx = 0;
4523-
for (expr* arg : *to_app(fn)) {
4524-
subst.push_back(m.mk_var(idx++, m.get_sort(arg)));
4525-
}
4526-
expr_ref bodyr(m);
4527-
var_subst sub(m, true);
4528-
TRACE("context", tout << expr_ref(q, m) << " " << subst << "\n";);
4529-
bodyr = sub(body, subst.size(), subst.c_ptr());
4530-
func_decl* f = to_app(fn)->get_decl();
4531-
func_interp* fi = alloc(func_interp, m, f->get_arity());
4532-
fi->set_else(bodyr);
4533-
m_model->register_decl(f, fi);
4534-
}
4535-
}
45364510
recfun::util u(m);
45374511
func_decl_ref_vector recfuns = u.get_rec_funs();
45384512
for (func_decl* f : recfuns) {

src/smt/smt_context_inv.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,6 @@ namespace smt {
367367
if (!is_ground(n)) {
368368
continue;
369369
}
370-
if (is_quantifier(n) && m.is_rec_fun_def(to_quantifier(n))) {
371-
continue;
372-
}
373370
switch (get_assignment(lit)) {
374371
case l_undef:
375372
break;

src/smt/smt_model_checker.cpp

Lines changed: 5 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ namespace smt {
4747
m_model_finder(mf),
4848
m_max_cexs(1),
4949
m_iteration_idx(0),
50-
m_has_rec_fun(false),
5150
m_curr_model(nullptr),
5251
m_fresh_exprs(m),
5352
m_pinned_exprs(m) {
@@ -380,36 +379,6 @@ namespace smt {
380379
return false;
381380
}
382381

383-
bool model_checker::check_rec_fun(quantifier* q, bool strict_rec_fun) {
384-
TRACE("model_checker", tout << mk_pp(q, m) << "\n";);
385-
SASSERT(q->get_num_patterns() == 2); // first pattern is the function, second is the body.
386-
func_decl* f = m.get_rec_fun_decl(q);
387-
388-
expr_ref_vector args(m);
389-
unsigned num_decls = q->get_num_decls();
390-
args.resize(num_decls, nullptr);
391-
var_subst sub(m);
392-
expr_ref tmp(m), result(m);
393-
for (enode* n : m_context->enodes_of(f)) {
394-
if (m_context->is_relevant(n)) {
395-
app* e = n->get_owner();
396-
SASSERT(e->get_num_args() == num_decls);
397-
for (unsigned i = 0; i < num_decls; ++i) {
398-
args[i] = e->get_arg(i);
399-
}
400-
tmp = sub(q->get_expr(), num_decls, args.c_ptr());
401-
TRACE("model_checker", tout << "curr_model:\n"; model_pp(tout, *m_curr_model););
402-
m_curr_model->eval(tmp, result, true);
403-
if (strict_rec_fun ? !m.is_true(result) : m.is_false(result)) {
404-
add_instance(q, args, 0, nullptr);
405-
return false;
406-
}
407-
TRACE("model_checker", tout << tmp << "\nevaluates to:\n" << result << "\n";);
408-
}
409-
}
410-
return true;
411-
}
412-
413382
void model_checker::init_aux_context() {
414383
if (!m_fparams) {
415384
m_fparams = alloc(smt_params, m_context->get_fparams());
@@ -458,7 +427,7 @@ namespace smt {
458427
bool found_relevant = false;
459428
unsigned num_failures = 0;
460429

461-
check_quantifiers(false, found_relevant, num_failures);
430+
check_quantifiers(found_relevant, num_failures);
462431

463432
if (found_relevant)
464433
m_iteration_idx++;
@@ -467,11 +436,11 @@ namespace smt {
467436
TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";);
468437
m_max_cexs += m_params.m_mbqi_max_cexs;
469438

470-
if (num_failures == 0 && (!m_context->validate_model() || has_rec_under_quantifiers())) {
439+
if (num_failures == 0 && (!m_context->validate_model())) {
471440
num_failures = 1;
472441
// this time force expanding recursive function definitions
473442
// that are not forced true in the current model.
474-
check_quantifiers(true, found_relevant, num_failures);
443+
check_quantifiers(found_relevant, num_failures);
475444
}
476445
if (num_failures == 0)
477446
m_curr_model->cleanup();
@@ -484,43 +453,6 @@ namespace smt {
484453
return num_failures == 0;
485454
}
486455

487-
struct has_rec_fun_proc {
488-
obj_hashtable<func_decl>& m_rec_funs;
489-
bool m_has_rec_fun;
490-
491-
bool has_rec_fun() const { return m_has_rec_fun; }
492-
493-
has_rec_fun_proc(obj_hashtable<func_decl>& rec_funs):
494-
m_rec_funs(rec_funs),
495-
m_has_rec_fun(false) {}
496-
497-
void operator()(app* fn) {
498-
m_has_rec_fun |= m_rec_funs.contains(fn->get_decl());
499-
}
500-
void operator()(expr*) {}
501-
};
502-
503-
bool model_checker::has_rec_under_quantifiers() {
504-
if (!m_has_rec_fun) {
505-
return false;
506-
}
507-
obj_hashtable<func_decl> rec_funs;
508-
for (quantifier * q : *m_qm) {
509-
if (m.is_rec_fun_def(q)) {
510-
rec_funs.insert(m.get_rec_fun_decl(q));
511-
}
512-
}
513-
expr_fast_mark1 visited;
514-
has_rec_fun_proc proc(rec_funs);
515-
for (quantifier * q : *m_qm) {
516-
if (!m.is_rec_fun_def(q)) {
517-
quick_for_each_expr(proc, visited, q);
518-
if (proc.has_rec_fun()) return true;
519-
}
520-
}
521-
return false;
522-
}
523-
524456
//
525457
// (repeated from defined_names.cpp)
526458
// NB. The pattern for lambdas is incomplete.
@@ -532,7 +464,7 @@ namespace smt {
532464
// using multi-patterns.
533465
//
534466

535-
void model_checker::check_quantifiers(bool strict_rec_fun, bool& found_relevant, unsigned& num_failures) {
467+
void model_checker::check_quantifiers(bool& found_relevant, unsigned& num_failures) {
536468
for (quantifier * q : *m_qm) {
537469
if (!(m_qm->mbqi_enabled(q) &&
538470
m_context->is_relevant(q) &&
@@ -549,14 +481,7 @@ namespace smt {
549481
verbose_stream() << "(smt.mbqi :checking " << q->get_qid() << ")\n";
550482
}
551483
found_relevant = true;
552-
if (m.is_rec_fun_def(q)) {
553-
m_has_rec_fun = true;
554-
if (!check_rec_fun(q, strict_rec_fun)) {
555-
TRACE("model_checker", tout << "checking recursive function failed\n";);
556-
num_failures++;
557-
}
558-
}
559-
else if (!check(q)) {
484+
if (!check(q)) {
560485
if (m_params.m_mbqi_trace || get_verbosity_level() >= 5) {
561486
IF_VERBOSE(0, verbose_stream() << "(smt.mbqi :failed " << q->get_qid() << ")\n");
562487
}

0 commit comments

Comments
 (0)