mirror of
https://github.com/Z3Prover/z3
synced 2025-11-05 22:06:03 +00:00
QEL: Fast Approximated Quantifier Elimination (#6820)
* qe_lite: cleanup and comment
no change to code
* mbp_arrays: refactor out partial equality (peq)
Partial array equality, PEQ, is used as an intermediate
expression during MBP for arrays. We need to factor it out
so that it can be shared between MBP-QEL and existing MBP.
Partial array equality (peq) is used in MBP for arrays.
Factoring this out to be used by multiple MBP implementations.
* rewriter: new rewrite rules
These rules are specializes for terms that are created in QEL.
QEL commit is comming later
* datatype_rw: new rewrite rule for ADTs
The rule handles this special case:
(cons (head x) (tail x)) --> x
* array_rewriter rules for rewriting PEQs
Special rules to simplify PEQs
* th_rewriter: wire PEQ simplifications
* spacer_iuc: avoid terms with default in IUC
Spacer prfers to not have a term representing default value of an array.
This guides IUC from picking such terms in interpolation
* mbp_term_graph: replace root with repr
* mbp_term_graph: formatting
* mbp_term_graph: class_props, getters, setters
Class properties allow to keep information for an equivalence class.
Getters and setters for terms allow accessing information
* mbp_term_graph: auxiliary methods for qel
QEL commit is comming later in the history
* mbp_term_graph: bug fix
* mbp_term_graph: pick, refine repr, compute cgrnd
* mbp_term_graph: internalize deq
* mbp_term_graph: constructor
* mbp_term_graph: optionally internalize equalities
Reperesent equalities explicitly by nodes in the term_graph
* qel
* formatting
* comments on term_lt
* get terms and other api for mbp_qel
* plugins for mbp_qel
* mbp_qel_util: utilities for mbp_qel
* qe_mbp: QEL-based mbp
* qel: expose QEL API
* spacer: replace qe_lite in qe_project_spacer by qel
This changes the default projection engine that spacer uses.
* cmd_context: debug commands for qel and mbp_qel
New commands are
mbp-qel -- MBP with term graphs
qel -- QEL with term graphs
qe-lite -- older qelite
* qe_mbp: model-based rewriters for arrays
* qe_mbp: QEL-based projection functions
* qsat: wire in QEL-based mbp
* qsat: debug code
* qsat: maybe a bug fix
Changed the code to follow the paper by adding all predicates above a given
level, not just predicates of immediately preceding level.
* chore: use new api to create solver in qsat
* mbp_term_graph use all_of idiom
* feat: solver for integer multiplication
* array_peq: formatting, no change to code
* mbp_qel_util: block comment + format
* mbt_term_graph: clang-format
* bug fix. Move dt rewrite to qe_mbp
* array_peq: add header
* run clang format on mbp plugins
* clang format on mul solver
* format do-while
* format
* format do-while
* update release notes
---------
Co-authored-by: hgvk94 <hgvk94@gmail.com>
Co-authored-by: Isabel Garcia <igarciac@uwaterloo.ca>
This commit is contained in:
parent
5b2519d7a3
commit
51d3c279d0
35 changed files with 4170 additions and 1517 deletions
|
|
@ -17,7 +17,6 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
|
||||
#include "util/lbool.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/expr_functors.h"
|
||||
|
|
@ -26,134 +25,11 @@ Revision History:
|
|||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/array_peq.h"
|
||||
#include "model/model_evaluator.h"
|
||||
#include "qe/mbp/mbp_arrays.h"
|
||||
#include "qe/mbp/mbp_term_graph.h"
|
||||
|
||||
|
||||
namespace {
|
||||
bool is_partial_eq (app* a);
|
||||
|
||||
/**
|
||||
* \brief utility class for partial equalities
|
||||
*
|
||||
* A partial equality (a ==I b), for two arrays a,b and a finite set of indices I holds
|
||||
* iff (Forall i. i \not\in I => a[i] == b[i]); in other words, it is a
|
||||
* restricted form of the extensionality axiom
|
||||
*
|
||||
* using this class, we denote (a =I b) as f(a,b,i0,i1,...)
|
||||
* where f is an uninterpreted predicate with name PARTIAL_EQ and
|
||||
* I = {i0,i1,...}
|
||||
*/
|
||||
|
||||
// TBD: make work for arrays with multiple arguments.
|
||||
class peq {
|
||||
ast_manager& m;
|
||||
expr_ref m_lhs;
|
||||
expr_ref m_rhs;
|
||||
vector<expr_ref_vector> m_diff_indices;
|
||||
func_decl_ref m_decl; // the partial equality declaration
|
||||
app_ref m_peq; // partial equality application
|
||||
app_ref m_eq; // equivalent std equality using def. of partial eq
|
||||
array_util m_arr_u;
|
||||
|
||||
public:
|
||||
static const char* PARTIAL_EQ;
|
||||
|
||||
peq (app* p, ast_manager& m):
|
||||
m (m),
|
||||
m_lhs (p->get_arg (0), m),
|
||||
m_rhs (p->get_arg (1), m),
|
||||
m_decl (p->get_decl (), m),
|
||||
m_peq (p, m),
|
||||
m_eq (m),
|
||||
m_arr_u (m)
|
||||
{
|
||||
VERIFY (is_partial_eq (p));
|
||||
SASSERT (m_arr_u.is_array (m_lhs) &&
|
||||
m_arr_u.is_array (m_rhs) &&
|
||||
m_lhs->get_sort() == m_rhs->get_sort());
|
||||
unsigned arity = get_array_arity(m_lhs->get_sort());
|
||||
for (unsigned i = 2; i < p->get_num_args (); i += arity) {
|
||||
SASSERT(arity + i <= p->get_num_args());
|
||||
expr_ref_vector vec(m);
|
||||
vec.append(arity, p->get_args() + i);
|
||||
m_diff_indices.push_back (vec);
|
||||
}
|
||||
}
|
||||
|
||||
peq (expr* lhs, expr* rhs, vector<expr_ref_vector> const& diff_indices, ast_manager& m):
|
||||
m (m),
|
||||
m_lhs (lhs, m),
|
||||
m_rhs (rhs, m),
|
||||
m_diff_indices (diff_indices),
|
||||
m_decl (m),
|
||||
m_peq (m),
|
||||
m_eq (m),
|
||||
m_arr_u (m) {
|
||||
SASSERT (m_arr_u.is_array (lhs) &&
|
||||
m_arr_u.is_array (rhs) &&
|
||||
lhs->get_sort() == rhs->get_sort());
|
||||
ptr_vector<sort> sorts;
|
||||
sorts.push_back (m_lhs->get_sort ());
|
||||
sorts.push_back (m_rhs->get_sort ());
|
||||
for (auto const& v : diff_indices) {
|
||||
SASSERT(v.size() == get_array_arity(m_lhs->get_sort()));
|
||||
for (expr* e : v)
|
||||
sorts.push_back (e->get_sort());
|
||||
}
|
||||
m_decl = m.mk_func_decl (symbol (PARTIAL_EQ), sorts.size (), sorts.data (), m.mk_bool_sort ());
|
||||
}
|
||||
|
||||
expr_ref lhs () { return m_lhs; }
|
||||
|
||||
expr_ref rhs () { return m_rhs; }
|
||||
|
||||
void get_diff_indices (vector<expr_ref_vector>& result) { result.append(m_diff_indices); }
|
||||
|
||||
app_ref mk_peq () {
|
||||
if (!m_peq) {
|
||||
ptr_vector<expr> args;
|
||||
args.push_back (m_lhs);
|
||||
args.push_back (m_rhs);
|
||||
for (auto const& v : m_diff_indices) {
|
||||
args.append (v.size(), v.data());
|
||||
}
|
||||
m_peq = m.mk_app (m_decl, args.size (), args.data ());
|
||||
}
|
||||
return m_peq;
|
||||
}
|
||||
|
||||
app_ref mk_eq (app_ref_vector& aux_consts, bool stores_on_rhs = true) {
|
||||
if (!m_eq) {
|
||||
expr_ref lhs (m_lhs, m), rhs (m_rhs, m);
|
||||
if (!stores_on_rhs) {
|
||||
std::swap (lhs, rhs);
|
||||
}
|
||||
// lhs = (...(store (store rhs i0 v0) i1 v1)...)
|
||||
sort* val_sort = get_array_range (lhs->get_sort());
|
||||
for (expr_ref_vector const& diff : m_diff_indices) {
|
||||
ptr_vector<expr> store_args;
|
||||
store_args.push_back (rhs);
|
||||
store_args.append (diff.size(), diff.data());
|
||||
app_ref val(m.mk_fresh_const ("diff", val_sort), m);
|
||||
store_args.push_back (val);
|
||||
aux_consts.push_back (val);
|
||||
rhs = m_arr_u.mk_store (store_args);
|
||||
}
|
||||
m_eq = m.mk_eq (lhs, rhs);
|
||||
}
|
||||
return m_eq;
|
||||
}
|
||||
};
|
||||
|
||||
const char* peq::PARTIAL_EQ = "!partial_eq";
|
||||
|
||||
bool is_partial_eq (app* a) {
|
||||
return a->get_decl ()->get_name () == peq::PARTIAL_EQ;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mbp {
|
||||
|
||||
|
||||
|
|
@ -366,20 +242,10 @@ namespace mbp {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mk (e0 ==indices e1)
|
||||
*
|
||||
* result has stores if either e0 or e1 or an index term has stores
|
||||
*/
|
||||
app_ref mk_peq (expr* e0, expr* e1, vector<expr_ref_vector> const& indices) {
|
||||
peq p (e0, e1, indices, m);
|
||||
return p.mk_peq ();
|
||||
}
|
||||
|
||||
void find_subst_term (app* eq) {
|
||||
SASSERT(m.is_eq(eq));
|
||||
vector<expr_ref_vector> empty;
|
||||
app_ref p_exp = mk_peq (eq->get_arg (0), eq->get_arg (1), empty);
|
||||
app_ref p_exp = mk_peq (eq->get_arg (0), eq->get_arg (1), empty, m);
|
||||
bool subst_eq_found = false;
|
||||
while (true) {
|
||||
TRACE ("qe", tout << "processing peq:\n" << p_exp << "\n";);
|
||||
|
|
@ -434,7 +300,7 @@ namespace mbp {
|
|||
);
|
||||
|
||||
// arr0 ==I arr1
|
||||
p_exp = mk_peq (arr0, arr1, I);
|
||||
p_exp = mk_peq (arr0, arr1, I, m);
|
||||
|
||||
TRACE ("qe",
|
||||
tout << "new peq:\n";
|
||||
|
|
@ -445,7 +311,7 @@ namespace mbp {
|
|||
m_idx_lits_v.append (idx_diseq);
|
||||
// arr0 ==I+idx arr1
|
||||
I.push_back (idxs);
|
||||
p_exp = mk_peq (arr0, arr1, I);
|
||||
p_exp = mk_peq (arr0, arr1, I, m);
|
||||
|
||||
TRACE ("qe", tout << "new peq:\n" << p_exp << "\n"; );
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue