3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-22 11:07:51 +00:00

move model and proof converters to self-contained module

This commit is contained in:
Nikolaj Bjorner 2022-11-03 05:23:01 -07:00
parent 7b12a5c5a8
commit 1dca6402fb
88 changed files with 170 additions and 134 deletions

View file

@ -0,0 +1,8 @@
z3_add_component(converters
SOURCES
model_converter.cpp
proof_converter.cpp
generic_model_converter.cpp
COMPONENT_DEPENDENCIES
model
)

View file

@ -0,0 +1,124 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
converter.h
Abstract:
Abstract class and templates for proof and model converters.
Author:
Leonardo (leonardo) 2011-11-14
Notes:
--*/
#pragma once
#include "util/vector.h"
#include "util/ref.h"
#include "ast/ast_translation.h"
class converter {
unsigned m_ref_count;
public:
converter():m_ref_count(0) {}
virtual ~converter() = default;
void inc_ref() { ++m_ref_count; }
void dec_ref() {
--m_ref_count;
if (m_ref_count == 0) {
dealloc(this);
}
}
virtual void cancel() {}
virtual void display(std::ostream & out) = 0;
};
template<typename T>
class concat_converter : public T {
protected:
ref<T> m_c1;
ref<T> m_c2;
template<typename T2>
T * translate_core(ast_translation & translator) {
T * t1 = m_c1->translate(translator);
T * t2 = m_c2->translate(translator);
return alloc(T2, t1, t2);
}
public:
concat_converter(T * c1, T * c2):m_c1(c1), m_c2(c2) {}
void cancel() override {
m_c2->cancel();
m_c1->cancel();
}
virtual char const * get_name() const = 0;
void display(std::ostream & out) override {
m_c1->display(out);
m_c2->display(out);
}
};
template<typename T>
class concat_star_converter : public T {
protected:
ref<T> m_c1;
ptr_vector<T> m_c2s;
unsigned_vector m_szs;
template<typename T2>
T * translate_core(ast_translation & translator) {
T * t1 = m_c1 ? m_c1->translate(translator) : nullptr;
ptr_buffer<T> t2s;
for (T* c : m_c2s)
t2s.push_back(c ? c->translate(translator) : nullptr);
return alloc(T2, t1, m_c2s.size(), t2s.data(), m_szs.data());
}
public:
concat_star_converter(T * c1, unsigned num, T * const * c2s, unsigned * szs):
m_c1(c1) {
for (unsigned i = 0; i < num; i++) {
T * c2 = c2s[i];
if (c2)
c2->inc_ref();
m_c2s.push_back(c2);
m_szs.push_back(szs[i]);
}
}
~concat_star_converter() override {
for (T* c : m_c2s)
if (c) c->dec_ref();
}
void cancel() override {
if (m_c1)
m_c1->cancel();
for (T* c : m_c2s)
if (c) c->cancel();
}
virtual char const * get_name() const = 0;
void display(std::ostream & out) override {
if (m_c1)
m_c1->display(out);
for (T* c : m_c2s)
if (c) c->display(out);
}
};

View file

@ -0,0 +1,218 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
generic_model_converter.cpp
Abstract:
Generic model converter that hides and adds entries.
It subsumes filter_model_converter and extension_model_converter.
Author:
Nikolaj Bjorner (nbjorner) 2017-10-29
Notes:
--*/
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/for_each_expr.h"
#include "ast/ast_util.h"
#include "ast/occurs.h"
#include "ast/rewriter/expr_safe_replace.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/converters/generic_model_converter.h"
#include "model/model_v2_pp.h"
#include "model/model_evaluator.h"
generic_model_converter::~generic_model_converter() {
}
void generic_model_converter::add(func_decl * d, expr* e) {
VERIFY(e);
VERIFY(d->get_range() == e->get_sort());
m_first_idx.insert_if_not_there(d, m_entries.size());
m_entries.push_back(entry(d, e, m, ADD));
}
void generic_model_converter::operator()(model_ref & md) {
TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout););
model_evaluator ev(*(md.get()));
ev.set_model_completion(true);
ev.set_expand_array_equalities(false);
expr_ref val(m);
unsigned arity;
bool reset_ev = false;
for (unsigned i = m_entries.size(); i-- > 0; ) {
entry const& e = m_entries[i];
switch (e.m_instruction) {
case instruction::HIDE:
md->unregister_decl(e.m_f);
break;
case instruction::ADD:
ev(e.m_def, val);
TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";);
arity = e.m_f->get_arity();
reset_ev = false;
if (arity == 0) {
expr* old_val = md->get_const_interp(e.m_f);
if (old_val && old_val == val) {
// skip
}
else {
reset_ev = old_val != nullptr;
md->register_decl(e.m_f, val);
}
}
else {
func_interp * old_val = md->get_func_interp(e.m_f);
if (old_val && old_val->get_else() == val) {
// skip
}
else {
reset_ev = old_val != nullptr;
func_interp * new_fi = alloc(func_interp, m, arity);
new_fi->set_else(val);
md->register_decl(e.m_f, new_fi);
}
}
if (reset_ev) {
ev.reset();
ev.set_model_completion(true);
ev.set_expand_array_equalities(false);
}
break;
}
}
TRACE("model_converter", tout << "after generic_model_converter\n"; model_v2_pp(tout, *md););
}
void generic_model_converter::display(std::ostream & out) {
for (entry const& e : m_entries) {
switch (e.m_instruction) {
case instruction::HIDE:
display_del(out, e.m_f);
break;
case instruction::ADD:
display_add(out, m, e.m_f, e.m_def);
break;
}
}
}
generic_model_converter * generic_model_converter::copy(ast_translation & translator) {
ast_manager& to = translator.to();
generic_model_converter * res = alloc(generic_model_converter, to, m_orig.c_str());
for (entry const& e : m_entries) {
func_decl_ref d(translator(e.m_f.get()), to);
switch (e.m_instruction) {
case instruction::HIDE:
res->hide(d);
break;
case instruction::ADD: {
expr_ref def(translator(e.m_def.get()), to);
res->add(d, def);
break;
}
}
}
return res;
}
void generic_model_converter::set_env(ast_pp_util* visitor) {
if (!visitor) {
m_env = nullptr;
}
else {
m_env = &visitor->env();
for (entry const& e : m_entries) {
visitor->coll.visit_func(e.m_f);
if (e.m_def) visitor->coll.visit(e.m_def);
}
}
}
void generic_model_converter::get_units(obj_map<expr, bool>& units) {
th_rewriter rw(m);
expr_safe_replace rep(m);
expr_ref tmp(m);
for (auto const& kv : units) {
rep.insert(kv.m_key, kv.m_value ? m.mk_true() : m.mk_false());
}
for (unsigned i = m_entries.size(); i-- > 0;) {
entry const& e = m_entries[i];
switch (e.m_instruction) {
case HIDE:
tmp = m.mk_const(e.m_f);
if (units.contains(tmp)) {
m.dec_ref(tmp);
units.remove(tmp);
}
break;
case ADD:
if (e.m_f->get_arity() == 0 && m.is_bool(e.m_f->get_range())) {
tmp = m.mk_const(e.m_f);
if (units.contains(tmp)) {
break;
}
tmp = e.m_def;
rep(tmp);
rw(tmp);
if (m.is_true(tmp)) {
tmp = m.mk_const(e.m_f);
m.inc_ref(tmp);
units.insert(tmp, true);
rep.insert(tmp, m.mk_true());
}
else if (m.is_false(tmp)) {
tmp = m.mk_const(e.m_f);
m.inc_ref(tmp);
units.insert(tmp, false);
rep.insert(tmp, m.mk_false());
}
}
break;
}
}
}
/*
\brief simplify definition expansion from model converter in the case they come from blocked clauses.
In this case the definitions are of the form:
x <=> x or not (C)
or dually,
x <=> not (not x or not C)
in either case the definitions simplify to
x or C
*/
expr_ref generic_model_converter::simplify_def(entry const& e) {
expr_ref c(m.mk_const(e.m_f), m);
if (m.is_bool(c) && occurs(c, e.m_def)) {
expr_safe_replace rep(m);
expr_ref result1 = e.m_def;
expr_ref result2 = e.m_def;
rep.apply_substitution(c, m.mk_true(), result1);
rep.apply_substitution(c, m.mk_false(), result2);
th_rewriter rw(m);
expr_ref result(m.mk_and(m.mk_implies(result2, c), m.mk_implies(c, result1)), m);
rw(result);
return result;
}
else {
return expr_ref(m.mk_eq(c, e.m_def), m);
}
}

View file

@ -0,0 +1,73 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
generic_model_converter.h
Abstract:
Generic model converter that hides and adds entries.
It subsumes filter_model_converter and extension_model_converter.
Author:
Nikolaj Bjorner (nbjorner) 2017-10-29
Notes:
--*/
#pragma once
#include "ast/converters/model_converter.h"
class generic_model_converter : public model_converter {
enum instruction { HIDE, ADD };
struct entry {
func_decl_ref m_f;
expr_ref m_def;
instruction m_instruction;
entry(func_decl* f, expr* d, ast_manager& m, instruction i):
m_f(f, m), m_def(d, m), m_instruction(i) {}
};
ast_manager& m;
std::string m_orig;
vector<entry> m_entries;
obj_map<func_decl, unsigned> m_first_idx;
expr_ref simplify_def(entry const& e);
public:
generic_model_converter(ast_manager & m, char const* orig) : m(m), m_orig(orig) {}
~generic_model_converter() override;
void hide(expr* e) { SASSERT(is_app(e) && to_app(e)->get_num_args() == 0); hide(to_app(e)->get_decl()); }
void hide(func_decl * f) { m_entries.push_back(entry(f, nullptr, m, HIDE)); }
void add(func_decl * d, expr* e);
void add(expr * d, expr* e) { SASSERT(is_app(d) && to_app(d)->get_num_args() == 0); add(to_app(d)->get_decl(), e); }
void operator()(labels_vec & labels) override {}
void operator()(model_ref & md) override;
void operator()(expr_ref& fml) override { UNREACHABLE(); }
void cancel() override {}
void display(std::ostream & out) override;
model_converter * translate(ast_translation & translator) override { return copy(translator); }
generic_model_converter* copy(ast_translation & translator);
void set_env(ast_pp_util* visitor) override;
void get_units(obj_map<expr, bool>& units) override;
};
typedef ref<generic_model_converter> generic_model_converter_ref;

View file

@ -0,0 +1,201 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
model_converter.h
Abstract:
Abstract interface for converting models.
Author:
Leonardo (leonardo) 2011-04-21
Notes:
--*/
#include "ast/converters/model_converter.h"
#include "model/model_v2_pp.h"
#include "ast/ast_smt2_pp.h"
/*
* Add or overwrite value in model.
*/
void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e) {
VERIFY(e);
VERIFY(f->get_range() == e->get_sort());
ast_smt2_pp(out, f, e, env, params_ref(), 0, "model-add") << "\n";
}
void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const {
smt2_pp_environment_dbg dbgenv(m);
smt2_pp_environment& env = m_env ? *m_env : dbgenv;
display_add(out, env, m, f, e);
}
/*
* A value is removed from the model.
*/
void model_converter::display_del(std::ostream& out, func_decl* f) const {
if (m_env) {
ast_smt2_pp(out << "(model-del ", f->get_name(), f->is_skolem(), *m_env) << ")\n";
}
else {
out << "(model-del " << f->get_name() << ")\n";
}
}
void model_converter::set_env(ast_pp_util* visitor) {
if (visitor) {
m_env = &visitor->env();
}
else {
m_env = nullptr;
}
}
void model_converter::display_add(std::ostream& out, ast_manager& m) {
// default printer for converter that adds entries
model_ref mdl = alloc(model, m);
(*this)(mdl);
smt2_pp_environment_dbg dbgenv(m);
smt2_pp_environment& env = m_env ? *m_env : dbgenv;
display_add(out, env, *mdl);
}
void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, model& mdl) {
ast_manager& m = mdl.get_manager();
for (unsigned i = 0, sz = mdl.get_num_constants(); i < sz; ++i) {
func_decl* f = mdl.get_constant(i);
display_add(out, env, m, f, mdl.get_const_interp(f));
}
for (unsigned i = 0, sz = mdl.get_num_functions(); i < sz; ++i) {
func_decl* f = mdl.get_function(i);
func_interp* fi = mdl.get_func_interp(f);
display_add(out, env, m, f, fi->get_interp());
}
}
class concat_model_converter : public concat_converter<model_converter> {
public:
concat_model_converter(model_converter * mc1, model_converter * mc2): concat_converter<model_converter>(mc1, mc2) {
VERIFY(m_c1 && m_c2);
}
void operator()(model_ref & m) override {
this->m_c2->operator()(m);
this->m_c1->operator()(m);
}
void operator()(expr_ref & fml) override {
this->m_c2->operator()(fml);
this->m_c1->operator()(fml);
}
void operator()(labels_vec & r) override {
this->m_c2->operator()(r);
this->m_c1->operator()(r);
}
void get_units(obj_map<expr, bool>& fmls) override {
m_c2->get_units(fmls);
m_c1->get_units(fmls);
}
char const * get_name() const override { return "concat-model-converter"; }
model_converter * translate(ast_translation & translator) override {
return this->translate_core<concat_model_converter>(translator);
}
void set_env(ast_pp_util* visitor) override {
this->m_c1->set_env(visitor);
this->m_c2->set_env(visitor);
}
};
model_converter * concat(model_converter * mc1, model_converter * mc2) {
if (mc1 == nullptr)
return mc2;
if (mc2 == nullptr)
return mc1;
return alloc(concat_model_converter, mc1, mc2);
}
class model2mc : public model_converter {
model_ref m_model;
labels_vec m_labels;
public:
model2mc(model * m):m_model(m) {}
model2mc(model * m, labels_vec const & r):m_model(m), m_labels(r) {}
void operator()(model_ref & m) override {
if (!m || !m_model) {
m = m_model;
return;
}
m->copy_const_interps(*m_model.get());
m->copy_func_interps(*m_model.get());
m->copy_usort_interps(*m_model.get());
}
void operator()(labels_vec & r) override {
r.append(m_labels.size(), m_labels.data());
}
void operator()(expr_ref& fml) override {
model::scoped_model_completion _scm(m_model, false);
fml = (*m_model)(fml);
}
void get_units(obj_map<expr, bool>& fmls) override {
// no-op
}
void cancel() override {
}
void display(std::ostream & out) override {
ast_manager& m = m_model->get_manager();
smt2_pp_environment_dbg dbgenv(m);
smt2_pp_environment& env = m_env ? *m_env : dbgenv;
model_converter::display_add(out, env, *m_model);
}
model_converter * translate(ast_translation & translator) override {
model * m = m_model->translate(translator);
return alloc(model2mc, m, m_labels);
}
};
model_converter * model2model_converter(model * m) {
if (!m) return nullptr;
return alloc(model2mc, m);
}
model_converter * model_and_labels2model_converter(model * m, labels_vec const & r) {
if (!m) return nullptr;
return alloc(model2mc, m, r);
}
void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m) {
if (mc) {
m = alloc(model, mng);
(*mc)(m);
}
}
void apply(model_converter_ref & mc, model_ref & m) {
if (mc) {
(*mc)(m);
}
}

View file

@ -0,0 +1,112 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
model_converter.h
Abstract:
Abstract interface for converting models.
Author:
Leonardo (leonardo) 2011-04-21
Notes:
A model converter, mc, can be used to convert a model for one
of a generated subgoal into a model for an initial goal or solver state.
For a goal or solver state that is decided, a model converter can be
a simple wrapper around a model.
Logically, given a formula F and subgoal formula F_s a model converter mc
for F_s relative to F has the property:
m |= F_s iff mc(m) |= F for every model m
For the evaluator associated with models, m, we expect
eval(m)(F_s) <=> eval(mc(m))(F)
This property holds for both eval, that decides on a fixed value
for constants that have no interpretation in m and for 'peval'
(partial eval) that returns just the constants that are unfixed.
(in the model evaluator one can control this behavior using a
configuration flag)
and more generally over the eval method have:
G => F_s iff peval(mc(e))(G) => F for every formula G
where e is the empty model (a model that does not evaluate any
When a model converter supports application to a formula it satisfies
the following property:
mc(G) & F_s is SAT iff G & F is SAT
For a model converter that is a sequence of definitions and removals
of functions we can obtain mc(G) by adding back or expanding definitions
that are required to interpret G fully in the context of F_s.
--*/
#pragma once
#include "util/ref.h"
#include "ast/ast_pp_util.h"
#include "model/model.h"
#include "ast/converters/converter.h"
class labels_vec : public svector<symbol> {};
class smt2_pp_environment;
class model_converter : public converter {
protected:
smt2_pp_environment* m_env;
static void display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e);
void display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const;
void display_del(std::ostream& out, func_decl* f) const;
void display_add(std::ostream& out, ast_manager& m);
public:
model_converter(): m_env(nullptr) {}
virtual void operator()(model_ref & m) = 0;
virtual void operator()(labels_vec & r) {}
virtual void operator()(expr_ref& fml) { UNREACHABLE(); }
virtual model_converter * translate(ast_translation & translator) = 0;
virtual void set_env(ast_pp_util* visitor);
/**
\brief we are adding a formula to the context of the model converter.
The operator has as side effect of adding definitions as assertions to the
formula and removing these definitions from the model converter.
*/
virtual void get_units(obj_map<expr, bool>& fmls) { UNREACHABLE(); }
static void display_add(std::ostream& out, smt2_pp_environment& env, model& mdl);
};
typedef ref<model_converter> model_converter_ref;
typedef sref_vector<model_converter> model_converter_ref_vector;
typedef sref_buffer<model_converter> model_converter_ref_buffer;
model_converter * concat(model_converter * mc1, model_converter * mc2);
model_converter * model2model_converter(model * m);
model_converter * model_and_labels2model_converter(model * m, labels_vec const &r);
void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m);
void apply(model_converter_ref & mc, model_ref & m);

View file

@ -0,0 +1,100 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
proof_converter.cpp
Abstract:
Abstract interface for converting proofs, and basic combinators
Author:
Leonardo (leonardo) 2011-11-14
Notes:
--*/
#include "ast/converters/proof_converter.h"
#include "ast/ast_smt2_pp.h"
class concat_proof_converter : public concat_converter<proof_converter> {
public:
concat_proof_converter(proof_converter * pc1, proof_converter * pc2):concat_converter<proof_converter>(pc1, pc2) {}
char const * get_name() const override { return "concat-proof-converter"; }
proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override {
proof_ref tmp(m);
tmp = this->m_c2->operator()(m, num_source, source);
proof * new_source = tmp.get();
return this->m_c1->operator()(m, 1, &new_source);
}
proof_converter * translate(ast_translation & translator) override {
return this->translate_core<concat_proof_converter>(translator);
}
};
proof_converter * concat(proof_converter * pc1, proof_converter * pc2) {
if (pc1 == nullptr)
return pc2;
if (pc2 == nullptr)
return pc1;
return alloc(concat_proof_converter, pc1, pc2);
}
class proof2pc : public proof_converter {
proof_ref m_pr;
public:
proof2pc(ast_manager & m, proof * pr):m_pr(pr, m) {}
proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override {
SASSERT(num_source == 0);
return m_pr;
}
proof_converter * translate(ast_translation & translator) override {
return alloc(proof2pc, translator.to(), translator(m_pr.get()));
}
void display(std::ostream & out) override {
out << "(proof->proof-converter-wrapper\n" << mk_ismt2_pp(m_pr.get(), m_pr.get_manager()) << ")\n";
}
};
proof_converter * proof2proof_converter(ast_manager & m, proof * pr) {
if (pr == nullptr)
return nullptr;
return alloc(proof2pc, m, pr);
}
void apply(ast_manager & m, proof_converter * pc, proof_ref & pr) {
if (pc) {
proof * _pr = pr.get();
pr = (*pc)(m, 1, &_pr);
}
}
/**
Let pc2s be a buffer of proof converters that are wrappers for proofs.
That is, they are functors of the form: unit -> Proof
Then, this function applies pc1 to the proofs produced by pc2s's and store
the resultant proof in result.
pc1 and pc2s must be different from 0.
*/
proof_ref apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s) {
SASSERT(pc1);
proof_ref_buffer prs(m);
unsigned sz = pc2s.size();
for (unsigned i = 0; i < sz; i++) {
proof_ref pr(m);
SASSERT(pc2s[i]); // proof production is enabled
pr = pc2s[i]->operator()(m, 0, nullptr);
prs.push_back(pr);
}
return (*pc1)(m, sz, prs.data());
}

View file

@ -0,0 +1,43 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
proof_converter.h
Abstract:
Abstract interface for converting proofs, and basic combinators.
Author:
Leonardo (leonardo) 2011-04-26
Notes:
--*/
#pragma once
#include "ast/ast.h"
#include "util/ref.h"
#include "ast/converters/converter.h"
class proof_converter : public converter {
public:
virtual proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) = 0;
virtual proof_converter * translate(ast_translation & translator) = 0;
};
typedef ref<proof_converter> proof_converter_ref;
typedef sref_vector<proof_converter> proof_converter_ref_vector;
typedef sref_buffer<proof_converter> proof_converter_ref_buffer;
proof_converter * concat(proof_converter * pc1, proof_converter * pc2);
proof_converter * proof2proof_converter(ast_manager & m, proof * pr);
void apply(ast_manager & m, proof_converter * pc, proof_ref & pr);
proof_ref apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s);

View file

@ -33,6 +33,7 @@ Author:
#include "util/statistics.h"
#include "util/params.h"
#include "ast/simplifiers/dependent_expr.h"
#include "ast/converters/model_converter.h"
/**
abstract interface to state updated by simplifiers.
@ -66,6 +67,7 @@ public:
virtual void collect_statistics(statistics& st) const {}
virtual void reset_statistics() {}
virtual void updt_params(params_ref const& p) {}
virtual model_converter_ref get_model_converter() { return model_converter_ref(); }
};
/**

View file

@ -23,6 +23,7 @@ Author:
#include "ast/recfun_decl_plugin.h"
#include "ast/rewriter/expr_replacer.h"
#include "ast/simplifiers/solve_eqs.h"
#include "ast/converters/generic_model_converter.h"
namespace euf {
@ -183,14 +184,16 @@ namespace euf {
m_unsafe_vars.mark(term);
}
#if 0
typedef generic_model_converter gmc;
model_converter_ref solve_eqs::get_model_converter() {
model_converter_ref mc = alloc(gmc, m, "solve-eqs");
for (unsigned id : m_subst_ids)
static_cast<gmc*>(mc.get())->add(id2var(id), m_subst->find(v));
for (unsigned id : m_subst_ids) {
auto* v = m_id2var[id];
static_cast<gmc*>(mc.get())->add(v, m_subst->find(v));
}
return mc;
}
#endif
solve_eqs::solve_eqs(ast_manager& m, dependent_expr_state& fmls) :
dependent_expr_simplifier(m, fmls), m_rewriter(m) {

View file

@ -18,9 +18,9 @@ Author:
#pragma once
#include "ast/rewriter/th_rewriter.h"
#include "ast/expr_substitution.h"
#include "util/scoped_ptr_vector.h"
#include "ast/expr_substitution.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/simplifiers/extract_eqs.h"
namespace euf {
@ -74,6 +74,6 @@ namespace euf {
void updt_params(params_ref const& p) override;
void collect_statistics(statistics& st) const override;
// model_converter_ref get_model_converter();
model_converter_ref get_model_converter() override;
};
}