mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 10:25:18 +00:00
eager quantifier instantiation for quantified array properties
This commit is contained in:
parent
2c7a39d580
commit
7168451201
|
@ -21,6 +21,8 @@ z3_add_component(transforms
|
|||
dl_mk_unbound_compressor.cpp
|
||||
dl_mk_unfold.cpp
|
||||
dl_transforms.cpp
|
||||
dl_mk_array_eq_rewrite.cpp
|
||||
dl_mk_array_instantiation.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
dataflow
|
||||
hilbert
|
||||
|
|
140
src/muz/transforms/dl_mk_array_eq_rewrite.cpp
Normal file
140
src/muz/transforms/dl_mk_array_eq_rewrite.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_mk_array_eq_rewrite.h
|
||||
|
||||
Abstract:
|
||||
Selects a representative for array equivalence classes.
|
||||
|
||||
Author:
|
||||
|
||||
Julien Braine
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "dl_mk_array_eq_rewrite.h"
|
||||
#include "dl_context.h"
|
||||
#include "pattern_inference.h"
|
||||
#include "dl_context.h"
|
||||
#include "expr_safe_replace.h"
|
||||
#include "expr_abstract.h"
|
||||
#include"fixedpoint_params.hpp"
|
||||
#include "../spacer/obj_equiv_class.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
mk_array_eq_rewrite::mk_array_eq_rewrite(
|
||||
context & ctx, unsigned priority):
|
||||
plugin(priority),
|
||||
m(ctx.get_manager()),
|
||||
m_ctx(ctx),
|
||||
m_a(m)
|
||||
{
|
||||
}
|
||||
|
||||
rule_set * mk_array_eq_rewrite::operator()(rule_set const & source)
|
||||
{
|
||||
src_set = &source;
|
||||
rule_set * result = alloc(rule_set, m_ctx);
|
||||
result->inherit_predicates(source);
|
||||
dst=result;
|
||||
unsigned nbrules = source.get_num_rules();
|
||||
src_manager = &source.get_rule_manager();
|
||||
for(unsigned i =0;i<nbrules;i++)
|
||||
{
|
||||
rule & r = *source.get_rule(i);
|
||||
instantiate_rule(r, *result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void mk_array_eq_rewrite::instantiate_rule(const rule& r, rule_set & dest)
|
||||
{
|
||||
//Reset everything
|
||||
cnt = src_manager->get_counter().get_max_rule_var(r)+1;
|
||||
|
||||
|
||||
expr_ref_vector new_tail(m);
|
||||
unsigned nb_predicates = r.get_uninterpreted_tail_size();
|
||||
unsigned tail_size = r.get_tail_size();
|
||||
for(unsigned i=0;i<nb_predicates;i++)
|
||||
{
|
||||
new_tail.push_back(r.get_tail(i));
|
||||
}
|
||||
|
||||
spacer::expr_equiv_class array_eq_classes(m);
|
||||
for(unsigned i=nb_predicates;i<tail_size;i++)
|
||||
{
|
||||
expr* cond = r.get_tail(i);
|
||||
expr* e1, *e2;
|
||||
if(m.is_eq(cond, e1, e2) && m_a.is_array(get_sort(e1)))
|
||||
{
|
||||
array_eq_classes.merge(e1, e2);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_tail.push_back(cond);
|
||||
}
|
||||
}
|
||||
|
||||
for(spacer::expr_equiv_class::equiv_iterator c_eq = array_eq_classes.begin();
|
||||
c_eq != array_eq_classes.end();++c_eq)
|
||||
{
|
||||
expr* representative = *(*c_eq).begin();
|
||||
for(spacer::expr_equiv_class::iterator it = (*c_eq).begin();
|
||||
it!=(*c_eq).end(); ++it)
|
||||
{
|
||||
if(!is_var(*it))
|
||||
{
|
||||
representative = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(spacer::expr_equiv_class::iterator it = (*c_eq).begin();
|
||||
it!=(*c_eq).end(); ++it)
|
||||
{
|
||||
for(unsigned i=0;i<new_tail.size();i++)
|
||||
new_tail[i] = replace(new_tail[i].get(), representative, *it);
|
||||
}
|
||||
for(spacer::expr_equiv_class::iterator it = (*c_eq).begin();
|
||||
it!=(*c_eq).end(); ++it)
|
||||
{
|
||||
new_tail.push_back(m.mk_eq(*it, representative));
|
||||
}
|
||||
}
|
||||
params_ref select_over_store;
|
||||
select_over_store.set_bool("expand_select_store", true);
|
||||
th_rewriter t(m, select_over_store);
|
||||
expr_ref_vector res_conjs(m);
|
||||
for(unsigned i=0;i<new_tail.size();i++)
|
||||
{
|
||||
expr_ref tmp(m);
|
||||
t(new_tail[i].get(), tmp);
|
||||
res_conjs.push_back(tmp);
|
||||
}
|
||||
proof_ref pr(m);
|
||||
src_manager->mk_rule(m.mk_implies(m.mk_and(res_conjs.size(), res_conjs.c_ptr()), r.get_head()), pr, dest, r.name());
|
||||
}
|
||||
|
||||
expr* mk_array_eq_rewrite::replace(expr* e, expr* new_val, expr* old_val)
|
||||
{
|
||||
if(e==old_val)
|
||||
return new_val;
|
||||
else if(!is_app(e))
|
||||
{
|
||||
return e;
|
||||
}
|
||||
app*f = to_app(e);
|
||||
ptr_vector<expr> n_args;
|
||||
for(unsigned i=0;i<f->get_num_args();i++)
|
||||
{
|
||||
n_args.push_back(replace(f->get_arg(i), new_val, old_val));
|
||||
}
|
||||
return m.mk_app(f->get_decl(), n_args.size(), n_args.c_ptr());
|
||||
}
|
||||
|
||||
}
|
54
src/muz/transforms/dl_mk_array_eq_rewrite.h
Normal file
54
src/muz/transforms/dl_mk_array_eq_rewrite.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_mk_array_eq_rewrite.h
|
||||
|
||||
Abstract:
|
||||
Selects a representative for array equivalence classes.
|
||||
|
||||
Author:
|
||||
|
||||
Julien Braine
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef DL_MK_ARRAY_EQ_REWRITE_H_
|
||||
#define DL_MK_ARRAY_EQ_REWRITE_H_
|
||||
|
||||
|
||||
#include "dl_rule_transformer.h"
|
||||
#include "../spacer/obj_equiv_class.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class context;
|
||||
class mk_array_eq_rewrite : public rule_transformer::plugin {
|
||||
//Context objects
|
||||
ast_manager& m;
|
||||
context& m_ctx;
|
||||
array_util m_a;
|
||||
|
||||
//Rule set context
|
||||
const rule_set*src_set;
|
||||
rule_set*dst;
|
||||
rule_manager* src_manager;
|
||||
unsigned cnt;//Index for new variables
|
||||
|
||||
expr* replace(expr* e, expr* new_val, expr* old_val);
|
||||
void instantiate_rule(const rule& r, rule_set & dest);
|
||||
|
||||
public:
|
||||
mk_array_eq_rewrite(context & ctx, unsigned priority);
|
||||
rule_set * operator()(rule_set const & source);
|
||||
virtual ~mk_array_eq_rewrite(){}
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* DL_MK_ARRAY_EQ_REWRITE_H_ */
|
||||
|
324
src/muz/transforms/dl_mk_array_instantiation.cpp
Normal file
324
src/muz/transforms/dl_mk_array_instantiation.cpp
Normal file
|
@ -0,0 +1,324 @@
|
|||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_mk_array_instantiation.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Does array instantiation
|
||||
|
||||
Author:
|
||||
|
||||
Julien Braine
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "dl_mk_array_instantiation.h"
|
||||
#include "dl_context.h"
|
||||
#include "pattern_inference.h"
|
||||
#include "dl_context.h"
|
||||
#include "expr_safe_replace.h"
|
||||
#include "expr_abstract.h"
|
||||
#include"fixedpoint_params.hpp"
|
||||
#include "../spacer/obj_equiv_class.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
mk_array_instantiation::mk_array_instantiation(
|
||||
context & ctx, unsigned priority):
|
||||
plugin(priority),
|
||||
m(ctx.get_manager()),
|
||||
m_ctx(ctx),
|
||||
m_a(m),
|
||||
eq_classes(m),
|
||||
ownership(m)
|
||||
{
|
||||
}
|
||||
|
||||
rule_set * mk_array_instantiation::operator()(rule_set const & source)
|
||||
{
|
||||
std::cout<<"Array Instantiation called with parameters :"
|
||||
<<" enforce="<<m_ctx.get_params().xform_instantiate_arrays_enforce()
|
||||
<<" nb_quantifier="<<m_ctx.get_params().xform_instantiate_arrays_nb_quantifier()
|
||||
<<" slice_technique="<<m_ctx.get_params().xform_instantiate_arrays_slice_technique()
|
||||
<<"\n";
|
||||
std::cout<<"Input rules = \n";
|
||||
source.display(std::cout);
|
||||
src_set = &source;
|
||||
rule_set * result = alloc(rule_set, m_ctx);
|
||||
dst=result;
|
||||
unsigned nbrules = source.get_num_rules();
|
||||
src_manager = &source.get_rule_manager();
|
||||
for(unsigned i =0;i<nbrules;i++)
|
||||
{
|
||||
rule & r = *source.get_rule(i);
|
||||
instantiate_rule(r, *result);
|
||||
}
|
||||
std::cout<<"\n\nOutput rules = \n";
|
||||
result->display(std::cout);
|
||||
return result;
|
||||
}
|
||||
|
||||
void mk_array_instantiation::instantiate_rule(const rule& r, rule_set & dest)
|
||||
{
|
||||
//Reset everything
|
||||
selects.reset();
|
||||
eq_classes.reset();
|
||||
cnt = src_manager->get_counter().get_max_rule_var(r)+1;
|
||||
done_selects.reset();
|
||||
ownership.reset();
|
||||
|
||||
expr_ref_vector phi(m);
|
||||
expr_ref_vector preds(m);
|
||||
expr_ref new_head = create_head(to_app(r.get_head()));
|
||||
unsigned nb_predicates = r.get_uninterpreted_tail_size();
|
||||
unsigned tail_size = r.get_tail_size();
|
||||
for(unsigned i=0;i<nb_predicates;i++)
|
||||
{
|
||||
preds.push_back(r.get_tail(i));
|
||||
}
|
||||
for(unsigned i=nb_predicates;i<tail_size;i++)
|
||||
{
|
||||
phi.push_back(r.get_tail(i));
|
||||
}
|
||||
|
||||
//Retrieve selects
|
||||
for(unsigned i=0;i<phi.size();i++)
|
||||
retrieve_selects(phi[i].get());
|
||||
|
||||
//Rewrite the predicates
|
||||
expr_ref_vector new_tail(m);
|
||||
for(unsigned i=0;i<preds.size();i++)
|
||||
{
|
||||
new_tail.append(instantiate_pred(to_app(preds[i].get())));
|
||||
}
|
||||
new_tail.append(phi);
|
||||
for(obj_map<expr, var*>::iterator it = done_selects.begin(); it!=done_selects.end(); ++it)
|
||||
{
|
||||
expr_ref tmp(m);
|
||||
tmp = &it->get_key();
|
||||
new_tail.push_back(m.mk_eq(it->get_value(), tmp));
|
||||
}
|
||||
proof_ref pr(m);
|
||||
src_manager->mk_rule(m.mk_implies(m.mk_and(new_tail.size(), new_tail.c_ptr()), new_head), pr, dest, r.name());
|
||||
}
|
||||
|
||||
expr_ref mk_array_instantiation::create_head(app* old_head)
|
||||
{
|
||||
expr_ref_vector new_args(m);
|
||||
for(unsigned i=0;i<old_head->get_num_args();i++)
|
||||
{
|
||||
expr*arg = old_head->get_arg(i);
|
||||
if(m_a.is_array(get_sort(arg)))
|
||||
{
|
||||
for(unsigned k=0; k< m_ctx.get_params().xform_instantiate_arrays_nb_quantifier();k++)
|
||||
{
|
||||
expr_ref_vector dummy_args(m);
|
||||
dummy_args.push_back(arg);
|
||||
for(unsigned i=0;i<get_array_arity(get_sort(arg));i++)
|
||||
{
|
||||
dummy_args.push_back(m.mk_var(cnt, get_array_domain(get_sort(arg), i)));
|
||||
cnt++;
|
||||
}
|
||||
expr_ref select(m);
|
||||
select = m_a.mk_select(dummy_args.size(), dummy_args.c_ptr());
|
||||
new_args.push_back(select);
|
||||
selects.insert_if_not_there(arg, ptr_vector<expr>());
|
||||
selects[arg].push_back(select);
|
||||
}
|
||||
if(!m_ctx.get_params().xform_instantiate_arrays_enforce())
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
else
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
return create_pred(old_head, new_args);
|
||||
}
|
||||
|
||||
|
||||
void mk_array_instantiation::retrieve_selects(expr* e)
|
||||
{
|
||||
//If the expression is not a function application, we ignore it
|
||||
if (!is_app(e)) {
|
||||
return;
|
||||
}
|
||||
app*f=to_app(e);
|
||||
//Call the function recursively on all arguments
|
||||
unsigned nbargs = f->get_num_args();
|
||||
for(unsigned i=0;i<nbargs;i++)
|
||||
{
|
||||
retrieve_selects(f->get_arg(i));
|
||||
}
|
||||
//If it is a select, then add it to selects
|
||||
if(m_a.is_select(f))
|
||||
{
|
||||
SASSERT(!m_a.is_array(get_sort(e)));
|
||||
selects.insert_if_not_there(f->get_arg(0), ptr_vector<expr>());
|
||||
selects[f->get_arg(0)].push_back(e);
|
||||
}
|
||||
//If it is a condition between arrays, for example the result of a store, then add it to the equiv_classes
|
||||
if(m_a.is_store(f))
|
||||
{
|
||||
eq_classes.merge(e, f->get_arg(0));
|
||||
}
|
||||
else if(m.is_eq(f) && m_a.is_array(get_sort(f->get_arg(0))))
|
||||
{
|
||||
eq_classes.merge(f->get_arg(0), f->get_arg(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
expr_ref_vector mk_array_instantiation::getId(app*old_pred, const expr_ref_vector& n_args)
|
||||
{
|
||||
expr_ref_vector res(m);
|
||||
for(unsigned i=0;i<n_args.size(); i++)
|
||||
{
|
||||
if(m_a.is_select(n_args[i]))
|
||||
{
|
||||
app*select = to_app(n_args[i]);
|
||||
for(unsigned j=1;j<select->get_num_args();j++)
|
||||
{
|
||||
res.push_back(select->get_arg(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref mk_array_instantiation::create_pred(app*old_pred, expr_ref_vector& n_args)
|
||||
{
|
||||
expr_ref_vector new_args(m);
|
||||
new_args.append(n_args);
|
||||
new_args.append(getId(old_pred, n_args));
|
||||
for(unsigned i=0;i<new_args.size();i++)
|
||||
{
|
||||
if(m_a.is_select(new_args[i].get()))
|
||||
{
|
||||
new_args[i] = mk_select_var(new_args[i].get());
|
||||
}
|
||||
}
|
||||
sort_ref_vector new_sorts(m);
|
||||
for(unsigned i=0;i<new_args.size();i++)
|
||||
new_sorts.push_back(get_sort(new_args[i].get()));
|
||||
expr_ref res(m);
|
||||
func_decl_ref fun_decl(m);
|
||||
fun_decl = m.mk_func_decl(symbol((old_pred->get_decl()->get_name().str()+"!inst").c_str()), new_sorts.size(), new_sorts.c_ptr(), old_pred->get_decl()->get_range());
|
||||
m_ctx.register_predicate(fun_decl, false);
|
||||
if(src_set->is_output_predicate(old_pred->get_decl()))
|
||||
dst->set_output_predicate(fun_decl);
|
||||
res=m.mk_app(fun_decl,new_args.size(), new_args.c_ptr());
|
||||
return res;
|
||||
}
|
||||
|
||||
var * mk_array_instantiation::mk_select_var(expr* select)
|
||||
{
|
||||
var*result;
|
||||
if(!done_selects.find(select, result))
|
||||
{
|
||||
ownership.push_back(select);
|
||||
result = m.mk_var(cnt, get_sort(select));
|
||||
cnt++;
|
||||
done_selects.insert(select, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref mk_array_instantiation::rewrite_select(expr*array, expr*select)
|
||||
{
|
||||
app*s = to_app(select);
|
||||
expr_ref res(m);
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(array);
|
||||
for(unsigned i=1; i<s->get_num_args();i++)
|
||||
{
|
||||
args.push_back(s->get_arg(i));
|
||||
}
|
||||
res = m_a.mk_select(args.size(), args.c_ptr());
|
||||
return res;
|
||||
}
|
||||
|
||||
expr_ref_vector mk_array_instantiation::retrieve_all_selects(expr*array)
|
||||
{
|
||||
expr_ref_vector all_selects(m);
|
||||
for(spacer::expr_equiv_class::iterator it = eq_classes.begin(array);
|
||||
it != eq_classes.end(array); ++it)
|
||||
{
|
||||
selects.insert_if_not_there(*it, ptr_vector<expr>());
|
||||
ptr_vector<expr>& select_ops = selects[*it];
|
||||
for(unsigned i=0;i<select_ops.size();i++)
|
||||
{
|
||||
all_selects.push_back(rewrite_select(array, select_ops[i]));
|
||||
}
|
||||
}
|
||||
if(all_selects.size()==0)
|
||||
{
|
||||
expr_ref_vector dummy_args(m);
|
||||
dummy_args.push_back(array);
|
||||
for(unsigned i=0;i<get_array_arity(get_sort(array));i++)
|
||||
{
|
||||
dummy_args.push_back(m.mk_var(cnt, get_array_domain(get_sort(array), i)));
|
||||
cnt++;
|
||||
}
|
||||
all_selects.push_back(m_a.mk_select(dummy_args.size(), dummy_args.c_ptr()));
|
||||
}
|
||||
return all_selects;
|
||||
}
|
||||
|
||||
|
||||
expr_ref_vector mk_array_instantiation::instantiate_pred(app*old_pred)
|
||||
{
|
||||
|
||||
unsigned nb_old_args=old_pred->get_num_args();
|
||||
//Stores, for each old position, the list of a new possible arguments
|
||||
vector<expr_ref_vector> arg_correspondance;
|
||||
for(unsigned i=0;i<nb_old_args;i++)
|
||||
{
|
||||
expr_ref arg(old_pred->get_arg(i), m);
|
||||
if(m_a.is_array(get_sort(arg)))
|
||||
{
|
||||
vector<expr_ref_vector> arg_possibilities(m_ctx.get_params().xform_instantiate_arrays_nb_quantifier(), retrieve_all_selects(arg));
|
||||
arg_correspondance.append(arg_possibilities);
|
||||
if(!m_ctx.get_params().xform_instantiate_arrays_enforce())
|
||||
{
|
||||
expr_ref_vector tmp(m);
|
||||
tmp.push_back(arg);
|
||||
arg_correspondance.push_back(tmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
expr_ref_vector tmp(m);
|
||||
tmp.push_back(arg);
|
||||
arg_correspondance.push_back(tmp);
|
||||
}
|
||||
}
|
||||
//Now, we need to deal with every combination
|
||||
|
||||
expr_ref_vector res(m);
|
||||
|
||||
svector<unsigned> chosen(arg_correspondance.size(), 0u);
|
||||
while(1)
|
||||
{
|
||||
expr_ref_vector new_args(m);
|
||||
for(unsigned i=0;i<chosen.size();i++)
|
||||
{
|
||||
new_args.push_back(arg_correspondance[i][chosen[i]].get());
|
||||
}
|
||||
res.push_back(create_pred(old_pred, new_args));
|
||||
unsigned pos=-1;
|
||||
do
|
||||
{
|
||||
pos++;
|
||||
if(pos==chosen.size())
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}while(chosen[pos]+1>=arg_correspondance[pos].size());
|
||||
chosen[pos]++;
|
||||
}
|
||||
}
|
||||
}
|
123
src/muz/transforms/dl_mk_array_instantiation.h
Normal file
123
src/muz/transforms/dl_mk_array_instantiation.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_mk_array_instantiation.h
|
||||
|
||||
Abstract:
|
||||
Transforms predicates so that array invariants can be discovered.
|
||||
|
||||
Motivation : Given a predicate P(a), no quantifier-free solution can express that P(a) <=> forall i, P(a[i]) = 0
|
||||
|
||||
Solution : Introduce a fresh variable i, and transform P(a) into P!inst(i, a).
|
||||
Now, (P!inst(i,a) := a[i] = 0) <=> P(a) := forall i, a[i] = 0.
|
||||
|
||||
Transformation on Horn rules:
|
||||
P(a, args) /\ phi(a, args, args') => P'(args') (for simplicity, assume there are no arrays in args').
|
||||
Is transformed into:
|
||||
(/\_r in read_indices(phi) P!inst(r, a, args)) /\ phi(a, args, args') => P'(args')
|
||||
|
||||
Limitations : This technique can only discover invariants on arrays that depend on one quantifier.
|
||||
Related work : Techniques relying on adding quantifiers and eliminating them. See dl_mk_quantifier_abstraction and dl_mk_quantifier_instantiation
|
||||
|
||||
Implementation:
|
||||
The implementation follows the solution suggested above, with more options. The addition of options implies that in the simple
|
||||
case described above, we in fact have P(a) transformed into P(i, a[i], a).
|
||||
|
||||
1) Dealing with multiple quantifiers -> The options fixedpoint.xform.instantiate_arrays.nb_quantifier gives the number of quantifiers per array.
|
||||
|
||||
2) Inforcing the instantiation -> We suggest an option (enforce_instantiation) to enforce this abstraction. This transforms
|
||||
P(a) into P(i, a[i]). This enforces the solver to limit the space search at the cost of imprecise results. This option
|
||||
corresponds to fixedpoint.xform.instantiate_arrays.enforce
|
||||
|
||||
3) Adding slices in the mix -> We wish to have the possibility to further restrict the search space: we want to smash cells, given a smashing rule.
|
||||
For example, in for loops j=0; j<n; j++, it might be relevant to restrict the search space and look for invariants that only depend on whether
|
||||
0<=i<j or j<=i, where i is the quantified variable.
|
||||
|
||||
Formally, a smashing rule is a function from the Index set (usually integer) to integers (the id set).
|
||||
GetId(i) should return the id of the set i belongs in.
|
||||
|
||||
In our example, we can give 0 as the id of the set {n, 0<=n<j} and 1 for the set {n, j<=n}, and -1 for the set {n, n<0}. We then have
|
||||
GetId(i) = ite(i<0, -1, ite(i<j, 0, 1))
|
||||
|
||||
Given that GetId function, P(a) /\ phi(a, ...) => P'(...) is transformed into
|
||||
(/\_r in read_indices(phi) P!inst(id_r, a[r], a) /\ GetId(r) = id_r) /\ phi(a, ...) => P'(...).
|
||||
Note : when no slicing is done, GetId(i) = i.
|
||||
This option corresponds to fixedpoint.xform.instantiate_arrays.slice_technique
|
||||
|
||||
Although we described GetId as returning integers, there is no reason to restrict the type of ids to integers. A more direct method,
|
||||
for the 0<=i<j or j<=i case could be :
|
||||
GetId(i) = (i<0, i<j)
|
||||
|
||||
GetId is even more powerful as we deal with the multiple quantifiers on multiple arrays.
|
||||
For example, we can use GetId to look for the same quantifiers in each array.
|
||||
Assume we have arrays a and b, instantiated with one quantifier each i and j.
|
||||
We can have GetId(i,j) = ite(i=j, (i, true), (fresh, false))
|
||||
|
||||
4) Reducing the set of r in read_indices(phi): in fact, we do not need to "instantiate" on all read indices of phi,
|
||||
we can restrict ourselves to those "linked" to a, through equalities and stores.
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Julien Braine
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef DL_MK_ARRAY_INSTANTIATION_H_
|
||||
#define DL_MK_ARRAY_INSTANTIATION_H_
|
||||
|
||||
|
||||
#include "dl_rule_transformer.h"
|
||||
#include "../spacer/obj_equiv_class.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class context;
|
||||
class mk_array_instantiation : public rule_transformer::plugin {
|
||||
//Context objects
|
||||
ast_manager& m;
|
||||
context& m_ctx;
|
||||
array_util m_a;
|
||||
|
||||
//Rule set context
|
||||
const rule_set*src_set;
|
||||
rule_set*dst;
|
||||
rule_manager* src_manager;
|
||||
|
||||
//Rule context
|
||||
obj_map<expr, ptr_vector<expr> > selects;
|
||||
spacer::expr_equiv_class eq_classes;
|
||||
unsigned cnt;//Index for new variables
|
||||
obj_map<expr, var*> done_selects;
|
||||
expr_ref_vector ownership;
|
||||
|
||||
//Helper functions
|
||||
void instantiate_rule(const rule& r, rule_set & dest);//Instantiates the rule
|
||||
void retrieve_selects(expr* e);//Retrieves all selects (fills the selects and eq_classes members)
|
||||
expr_ref rewrite_select(expr*array, expr*select);//Rewrites select(a, args) to select(array, args)
|
||||
expr_ref_vector retrieve_all_selects(expr*array);//Retrieves all selects linked to a given array (using eq classes and selects)
|
||||
expr_ref_vector instantiate_pred(app*old_pred);//Returns all the instantiation of a given predicate
|
||||
expr_ref create_pred(app*old_pred, expr_ref_vector& new_args);//Creates a predicate
|
||||
expr_ref create_head(app* old_head);//Creates the new head
|
||||
var * mk_select_var(expr* select);
|
||||
|
||||
/*Given the old predicate, and the new arguments for the new predicate, returns the new setId arguments.
|
||||
By default getId(P(x, y, a, b), (x, y, a[i], a[j], a, b[k], b[l], b)) (nb_quantifier=2, enforce=false)
|
||||
returns (i,j,k,l)
|
||||
So that the final created predicate is P!inst(x, y, a[i], a[j], a, b[k], b[l], b, i, j, k, l)
|
||||
*/
|
||||
expr_ref_vector getId(app*old_pred, const expr_ref_vector& new_args);
|
||||
public:
|
||||
mk_array_instantiation(context & ctx, unsigned priority);
|
||||
rule_set * operator()(rule_set const & source);
|
||||
virtual ~mk_array_instantiation(){}
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* DL_MK_ARRAY_INSTANTIATION_H_ */
|
|
@ -33,7 +33,8 @@ Revision History:
|
|||
#include "muz/transforms/dl_mk_quantifier_instantiation.h"
|
||||
#include "muz/transforms/dl_mk_subsumption_checker.h"
|
||||
#include "muz/transforms/dl_mk_scale.h"
|
||||
#include"fixedpoint_params.hpp"
|
||||
#include "muz/base/fixedpoint_params.hpp"
|
||||
#include "muz/transforms/dl_mk_array_eq_rewrite.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
@ -46,6 +47,11 @@ namespace datalog {
|
|||
transf.register_plugin(alloc(datalog::mk_coi_filter, ctx));
|
||||
transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx));
|
||||
|
||||
if (ctx.get_params().xform_instantiate_arrays()) {
|
||||
transf.register_plugin(alloc(datalog::mk_array_instantiation, ctx, 34999));
|
||||
}
|
||||
if(ctx.get_params().xform_transform_arrays())
|
||||
transf.register_plugin(alloc(datalog::mk_array_eq_rewrite, ctx, 34998));
|
||||
if (ctx.get_params().xform_quantify_arrays()) {
|
||||
transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, ctx, 38000));
|
||||
}
|
||||
|
@ -83,7 +89,7 @@ namespace datalog {
|
|||
transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010));
|
||||
transf.register_plugin(alloc(datalog::mk_scale, ctx, 36030));
|
||||
if (!ctx.get_params().xform_quantify_arrays()) {
|
||||
transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000));
|
||||
transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 35999));
|
||||
}
|
||||
if (ctx.get_params().xform_magic()) {
|
||||
transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020));
|
||||
|
|
Loading…
Reference in a new issue