mirror of
https://github.com/Z3Prover/z3
synced 2026-01-28 21:08:43 +00:00
Subterms Theory (#8115)
* somewhaat failed attempt at declaring subterm predicate I can't really figure out how to link the smt parser to the rest of the machinenery, so I will stop here and try from the other side. I'll start implmenting the logic and see if it brings me back to the parser. * initial logic implmentation Very primitive, but I don't like have that much work uncommitted. * parser implementation * more theory * Working base * subterm reflexivity * a few optimization Skip adding obvious equalities or disequality * removed some optimisations * better handling of backtracking * stupid segfault Add m_subterm to the trail * Update src/smt/theory_datatype.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/ast/rewriter/datatype_rewriter.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/smt/theory_datatype.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/smt/theory_datatype.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/smt/theory_datatype.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * review * forgot to update `iterate_subterm`'s signature * fix iterator segfault * Remove duplicate include statement Removed duplicate include of 'theory_datatype.h'. * Replace 'optional' with 'std::option' in datatype_decl_plugin.h * Add is_subterm_predicate matcher to datatype_decl_plugin * Change std::option to std::optional for m_subterm * Update pdecl.h * Change has_subterm to use has_value method * Update pdecl.cpp --------- Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
7377d28c30
commit
deaced1711
9 changed files with 563 additions and 32 deletions
|
|
@ -57,6 +57,23 @@ namespace datatype {
|
|||
return alloc(accessor, tr.to(), name(), to_sort(tr(m_range.get())));
|
||||
}
|
||||
|
||||
def const& subterm::get_def() const { return *m_def; }
|
||||
util& subterm::u() const { return m_def->u(); }
|
||||
|
||||
func_decl_ref subterm::instantiate(sort_ref_vector const& ps) const {
|
||||
ast_manager& m = ps.get_manager();
|
||||
sort_ref dt_sort = get_def().instantiate(ps);
|
||||
sort* domain[2] = { dt_sort, dt_sort };
|
||||
sort_ref range(m.mk_bool_sort(), m);
|
||||
parameter p(name());
|
||||
return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_SUBTERM, 1, &p, 2, domain, range), m);
|
||||
}
|
||||
|
||||
func_decl_ref subterm::instantiate(sort* dt) const {
|
||||
sort_ref_vector sorts = get_def().u().datatype_params(dt);
|
||||
return instantiate(sorts);
|
||||
}
|
||||
|
||||
constructor::~constructor() {
|
||||
for (accessor* a : m_accessors) dealloc(a);
|
||||
m_accessors.reset();
|
||||
|
|
@ -235,6 +252,7 @@ namespace datatype {
|
|||
|
||||
void plugin::reset() {
|
||||
m_datatype2constructors.reset();
|
||||
m_datatype2subterm.reset();
|
||||
m_datatype2nonrec_constructor.reset();
|
||||
m_constructor2accessors.reset();
|
||||
m_constructor2recognizer.reset();
|
||||
|
|
@ -443,6 +461,18 @@ namespace datatype {
|
|||
return m.mk_func_decl(name, arity, domain, range, info);
|
||||
}
|
||||
|
||||
func_decl * decl::plugin::mk_subterm(unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort* range)
|
||||
{
|
||||
ast_manager& m = *m_manager;
|
||||
VALIDATE_PARAM(num_parameters == 1 && parameters[0].is_symbol());
|
||||
VALIDATE_PARAM(arity == 2 && u().is_datatype(domain[0]) && domain[0] == domain[1] && m.is_bool(range));
|
||||
func_decl_info info(m_family_id, OP_DT_SUBTERM, num_parameters, parameters);
|
||||
info.m_private_parameters = true;
|
||||
symbol name = parameters[0].get_symbol();
|
||||
return m.mk_func_decl(name, arity, domain, range, info);
|
||||
}
|
||||
|
||||
func_decl * decl::plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
switch (k) {
|
||||
|
|
@ -453,7 +483,9 @@ namespace datatype {
|
|||
case OP_DT_IS:
|
||||
return mk_is(num_parameters, parameters, arity, domain, range);
|
||||
case OP_DT_ACCESSOR:
|
||||
return mk_accessor(num_parameters, parameters, arity, domain, range);
|
||||
return mk_accessor(num_parameters, parameters, arity, domain, range);
|
||||
case OP_DT_SUBTERM:
|
||||
return mk_subterm(num_parameters, parameters, arity, domain, range);
|
||||
case OP_DT_UPDATE_FIELD:
|
||||
return mk_update_field(num_parameters, parameters, arity, domain, range);
|
||||
default:
|
||||
|
|
@ -1040,6 +1072,22 @@ namespace datatype {
|
|||
return m_family_id;
|
||||
}
|
||||
|
||||
func_decl * util::get_datatype_subterm(sort * ty) {
|
||||
SASSERT(is_datatype(ty));
|
||||
func_decl * r = nullptr;
|
||||
if (plugin().m_datatype2subterm.find(ty, r))
|
||||
return r;
|
||||
|
||||
def const& d = get_def(ty);
|
||||
if (d.has_subterm()) {
|
||||
func_decl_ref f = d.get_subterm().instantiate(ty);
|
||||
r = f;
|
||||
plugin().add_ast(r);
|
||||
plugin().m_datatype2subterm.insert(ty, r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
ptr_vector<func_decl> const * util::get_datatype_constructors(sort * ty) {
|
||||
SASSERT(is_datatype(ty));
|
||||
ptr_vector<func_decl> * r = nullptr;
|
||||
|
|
@ -1482,11 +1530,14 @@ namespace datatype {
|
|||
|
||||
}
|
||||
|
||||
datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs) {
|
||||
datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs, symbol const& subterm_name) {
|
||||
datatype::decl::plugin& p = u.plugin();
|
||||
datatype::def* d = p.mk(n, num_params, params);
|
||||
for (unsigned i = 0; i < num_constructors; ++i) {
|
||||
d->add(cs[i]);
|
||||
}
|
||||
if (subterm_name != symbol::null) {
|
||||
d->attach_subterm(subterm_name, u.get_manager().mk_bool_sort());
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ enum op_kind {
|
|||
OP_DT_IS,
|
||||
OP_DT_ACCESSOR,
|
||||
OP_DT_UPDATE_FIELD,
|
||||
OP_DT_SUBTERM,
|
||||
LAST_DT_OP
|
||||
};
|
||||
|
||||
|
|
@ -48,6 +49,22 @@ namespace datatype {
|
|||
class def;
|
||||
class accessor;
|
||||
class constructor;
|
||||
class subterm;
|
||||
|
||||
class subterm {
|
||||
symbol m_name;
|
||||
sort_ref m_range;
|
||||
def* m_def = nullptr;
|
||||
public:
|
||||
subterm(ast_manager& m, symbol const& n, sort* r) : m_name(n), m_range(r, m) {}
|
||||
sort* range() const { return m_range; }
|
||||
symbol const& name() const { return m_name; }
|
||||
func_decl_ref instantiate(sort_ref_vector const& ps) const;
|
||||
func_decl_ref instantiate(sort* dt) const;
|
||||
util& u() const;
|
||||
void attach(def* d) { m_def = d; }
|
||||
def const& get_def() const;
|
||||
};
|
||||
|
||||
|
||||
class accessor {
|
||||
|
|
@ -166,6 +183,7 @@ namespace datatype {
|
|||
mutable sort_ref m_sort;
|
||||
ptr_vector<constructor> m_constructors;
|
||||
mutable dictionary<constructor*> m_name2constructor;
|
||||
std::optional<subterm> m_subterm;
|
||||
public:
|
||||
def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params):
|
||||
m(m),
|
||||
|
|
@ -185,6 +203,10 @@ namespace datatype {
|
|||
m_constructors.push_back(c);
|
||||
c->attach(this);
|
||||
}
|
||||
void attach_subterm(symbol const& n, sort* range) {
|
||||
m_subterm = subterm(m, n, range);
|
||||
m_subterm->attach(this);
|
||||
}
|
||||
symbol const& name() const { return m_name; }
|
||||
unsigned id() const { return m_class_id; }
|
||||
sort_ref instantiate(sort_ref_vector const& ps) const;
|
||||
|
|
@ -222,6 +244,8 @@ namespace datatype {
|
|||
SASSERT(result); // Post-condition: get_constructor_by_name returns a non-null result
|
||||
return result;
|
||||
}
|
||||
bool has_subterm() const { return m_subterm.has_value(); }
|
||||
subterm const& get_subterm() const { return *m_subterm; }
|
||||
def* translate(ast_translation& tr, util& u);
|
||||
};
|
||||
|
||||
|
|
@ -293,6 +317,7 @@ namespace datatype {
|
|||
|
||||
|
||||
obj_map<sort, ptr_vector<func_decl>*> m_datatype2constructors;
|
||||
obj_map<sort, func_decl*> m_datatype2subterm;
|
||||
obj_map<sort, cnstr_depth> m_datatype2nonrec_constructor;
|
||||
obj_map<func_decl, ptr_vector<func_decl>*> m_constructor2accessors;
|
||||
obj_map<func_decl, func_decl*> m_constructor2recognizer;
|
||||
|
|
@ -324,6 +349,16 @@ namespace datatype {
|
|||
unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range);
|
||||
|
||||
/**
|
||||
* \brief declares a subterm predicate
|
||||
*
|
||||
* Subterms have the signature `sort -> sort -> bool` and are only
|
||||
* supported for non-mutually recursive datatypes
|
||||
*/
|
||||
func_decl * mk_subterm(
|
||||
unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range);
|
||||
|
||||
func_decl * mk_recognizer(
|
||||
unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range);
|
||||
|
|
@ -379,6 +414,8 @@ namespace datatype {
|
|||
bool is_is(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_IS); }
|
||||
bool is_accessor(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_ACCESSOR); }
|
||||
bool is_update_field(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_UPDATE_FIELD); }
|
||||
bool is_subterm_predicate(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_SUBTERM); }
|
||||
bool is_subterm_predicate(expr* e) const { return is_app(e) && is_subterm_predicate(to_app(e)->get_decl()); }
|
||||
bool is_constructor(app const * f) const { return is_app_of(f, fid(), OP_DT_CONSTRUCTOR); }
|
||||
bool is_constructor(expr const * e) const { return is_app(e) && is_constructor(to_app(e)); }
|
||||
bool is_recognizer0(app const* f) const { return is_app_of(f, fid(), OP_DT_RECOGNISER);}
|
||||
|
|
@ -393,6 +430,7 @@ namespace datatype {
|
|||
bool is_update_field(expr * f) const { return is_app(f) && is_app_of(to_app(f), fid(), OP_DT_UPDATE_FIELD); }
|
||||
app* mk_is(func_decl * c, expr *f);
|
||||
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
|
||||
func_decl * get_datatype_subterm(sort * ty);
|
||||
unsigned get_datatype_num_constructors(sort * ty);
|
||||
unsigned get_datatype_num_parameter_sorts(sort * ty);
|
||||
sort* get_datatype_parameter_sort(sort * ty, unsigned idx);
|
||||
|
|
@ -468,7 +506,7 @@ inline constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r
|
|||
|
||||
|
||||
// Remark: the datatype becomes the owner of the constructor_decls
|
||||
datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs);
|
||||
datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs, symbol const& subterm_name = symbol::null);
|
||||
inline void del_datatype_decl(datatype_decl * d) {}
|
||||
inline void del_datatype_decls(unsigned num, datatype_decl * const * ds) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
|
|||
result = m().mk_app(c_decl, num, new_args.data());
|
||||
return BR_DONE;
|
||||
}
|
||||
case OP_DT_SUBTERM:
|
||||
// No rewrite yet for subterms
|
||||
return BR_FAILED;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue