3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-29 03:45:51 +00:00

added mbqi.id option, working on quantifiers in duality

This commit is contained in:
Ken McMillan 2013-12-10 11:41:25 -08:00
parent a3462ba6aa
commit 56b3406ee5
14 changed files with 409 additions and 33 deletions

View file

@ -79,9 +79,12 @@ namespace Duality {
int CumulativeDecisions();
int CountOperators(const Term &t);
private:
void SummarizeRec(hash_set<ast> &memo, std::vector<expr> &lits, int &ops, const Term &t);
int CountOperatorsRec(hash_set<ast> &memo, const Term &t);
};
@ -280,7 +283,7 @@ namespace Duality {
public:
std::list<Edge *> edges;
std::list<Node *> nodes;
std::list<Edge *> constraints;
std::list<std::pair<Edge *,Term> > constraints;
};
@ -556,6 +559,7 @@ namespace Duality {
edge to their values in the current assignment. */
void FixCurrentState(Edge *root);
void FixCurrentStateFull(Edge *edge);
/** Declare a constant in the background theory. */
@ -653,7 +657,11 @@ namespace Duality {
Term ComputeUnderapprox(Node *root, int persist);
/** Try to strengthen the annotation of a node by removing disjuncts. */
void Generalize(Node *node);
void Generalize(Node *root, Node *node);
/** Compute disjunctive interpolant for node by case splitting */
void InterpolateByCases(Node *root, Node *node);
/** Push a scope. Assertions made after Push can be undone by Pop. */
@ -687,6 +695,10 @@ namespace Duality {
void Pop(int num_scopes);
/** Erase the proof by performing a Pop, Push and re-assertion of
all the popped constraints */
void PopPush();
/** Return true if the given edge is used in the proof of unsat.
Can be called only after Solve or Check returns an unsat result. */
@ -861,6 +873,11 @@ namespace Duality {
Term UnderapproxFormula(const Term &f, hash_set<ast> &dont_cares);
void ImplicantFullRed(hash_map<ast,int> &memo, const Term &f, std::vector<Term> &lits,
hash_set<ast> &done, hash_set<ast> &dont_cares);
Term UnderapproxFullFormula(const Term &f, hash_set<ast> &dont_cares);
Term ToRuleRec(Edge *e, hash_map<ast,Term> &memo, const Term &t, std::vector<expr> &quants);
hash_map<ast,Term> resolve_ite_memo;
@ -896,6 +913,11 @@ namespace Duality {
expr SimplifyOr(std::vector<expr> &lits);
void SetAnnotation(Node *root, const expr &t);
void AddEdgeToSolver(Edge *edge);
void AddToProofCore(hash_set<ast> &core);
};
/** RPFP solver base class. */

View file

@ -125,6 +125,32 @@ namespace Duality {
}
}
int Z3User::CountOperatorsRec(hash_set<ast> &memo, const Term &t){
if(memo.find(t) != memo.end())
return 0;
memo.insert(t);
if(t.is_app()){
decl_kind k = t.decl().get_decl_kind();
if(k == And || k == Or){
int count = 1;
int nargs = t.num_args();
for(int i = 0; i < nargs; i++)
count += CountOperatorsRec(memo,t.arg(i));
return count;
}
return 0;
}
if(t.is_quantifier())
return CountOperatorsRec(memo,t.body())+1;
return 0;
}
int Z3User::CountOperators(const Term &t){
hash_set<ast> memo;
return CountOperatorsRec(memo,t);
}
Z3User::Term Z3User::conjoin(const std::vector<Term> &args){
return ctx.make(And,args);
}
@ -329,7 +355,15 @@ namespace Duality {
res = f(args.size(),&args[0]);
}
else if (t.is_quantifier())
res = CloneQuantifier(t,SubstRec(memo, t.body()));
{
std::vector<expr> pats;
t.get_patterns(pats);
for(unsigned i = 0; i < pats.size(); i++)
pats[i] = SubstRec(memo,pats[i]);
Term body = SubstRec(memo,t.body());
res = clone_quantifier(t, body, pats);
}
// res = CloneQuantifier(t,SubstRec(memo, t.body()));
else res = t;
return res;
}
@ -552,7 +586,7 @@ namespace Duality {
void RPFP::ConstrainEdgeLocalized(Edge *e, const Term &tl)
{
e->constraints.push_back(tl);
stack.back().constraints.push_back(e);
stack.back().constraints.push_back(std::pair<Edge *,Term>(e,tl));
slvr.add(tl);
}
@ -1142,7 +1176,8 @@ namespace Duality {
}
}
/* Unreachable! */
std::cerr << "error in RPFP::ImplicantRed";
// TODO: need to indicate this failure to caller
// std::cerr << "error in RPFP::ImplicantRed";
goto done;
}
else if(k == Not) {
@ -1161,6 +1196,31 @@ namespace Duality {
done[truth].insert(f);
}
void RPFP::ImplicantFullRed(hash_map<ast,int> &memo, const Term &f, std::vector<Term> &lits,
hash_set<ast> &done, hash_set<ast> &dont_cares){
if(done.find(f) != done.end())
return; /* already processed */
if(f.is_app()){
int nargs = f.num_args();
decl_kind k = f.decl().get_decl_kind();
if(k == Implies || k == Iff || k == And || k == Or || k == Not){
for(int i = 0; i < nargs; i++)
ImplicantFullRed(memo,f.arg(i),lits,done,dont_cares);
goto done;
}
}
{
if(dont_cares.find(f) == dont_cares.end()){
int b = SubtermTruth(memo,f);
if(b != 0 && b != 1) goto done;
expr bv = (b==1) ? f : !f;
lits.push_back(bv);
}
}
done:
done.insert(f);
}
RPFP::Term RPFP::ResolveIte(hash_map<ast,int> &memo, const Term &t, std::vector<Term> &lits,
hash_set<ast> *done, hash_set<ast> &dont_cares){
if(resolve_ite_memo.find(t) != resolve_ite_memo.end())
@ -1223,6 +1283,16 @@ namespace Duality {
return conjoin(lits);
}
RPFP::Term RPFP::UnderapproxFullFormula(const Term &f, hash_set<ast> &dont_cares){
/* first compute truth values of subterms */
hash_map<ast,int> memo;
hash_set<ast> done;
std::vector<Term> lits;
ImplicantFullRed(memo,f,lits,done,dont_cares);
/* return conjunction of literals */
return conjoin(lits);
}
struct VariableProjector : Z3User {
struct elim_cand {
@ -1759,6 +1829,17 @@ namespace Duality {
ConstrainEdgeLocalized(edge,eu);
}
void RPFP::FixCurrentStateFull(Edge *edge){
hash_set<ast> dont_cares;
resolve_ite_memo.clear();
timer_start("UnderapproxFormula");
Term dual = edge->dual.null() ? ctx.bool_val(true) : edge->dual;
for(unsigned i = 0; i < edge->constraints.size(); i++)
dual = dual && edge->constraints[i];
Term eu = UnderapproxFullFormula(dual,dont_cares);
timer_stop("UnderapproxFormula");
ConstrainEdgeLocalized(edge,eu);
}
RPFP::Term RPFP::ModelValueAsConstraint(const Term &t){
@ -1803,6 +1884,7 @@ namespace Duality {
res = CreateRelation(p->Annotation.IndParams,funder);
}
#if 0
void RPFP::GreedyReduce(solver &s, std::vector<expr> &conjuncts){
// verify
s.push();
@ -1829,6 +1911,36 @@ namespace Duality {
}
}
}
#endif
void RPFP::GreedyReduce(solver &s, std::vector<expr> &conjuncts){
std::vector<expr> lits(conjuncts.size());
for(unsigned i = 0; i < lits.size(); i++){
func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort());
lits[i] = pred();
s.add(ctx.make(Implies,lits[i],conjuncts[i]));
}
// verify
check_result res = s.check(lits.size(),&lits[0]);
if(res != unsat)
throw "should be unsat";
for(unsigned i = 0; i < conjuncts.size(); ){
std::swap(conjuncts[i],conjuncts.back());
std::swap(lits[i],lits.back());
check_result res = s.check(lits.size()-1,&lits[0]);
if(res != unsat){
std::swap(conjuncts[i],conjuncts.back());
std::swap(lits[i],lits.back());
i++;
}
else {
conjuncts.pop_back();
lits.pop_back();
}
}
}
void RPFP::NegateLits(std::vector<expr> &lits){
for(unsigned i = 0; i < lits.size(); i++){
@ -1848,20 +1960,56 @@ namespace Duality {
return ctx.make(Or,lits);
}
void RPFP::Generalize(Node *node){
std::vector<expr> conjuncts;
expr fmla = GetAnnotation(node);
CollectConjuncts(fmla,conjuncts,false);
// try to remove conjuncts one at a tme
aux_solver.push();
Edge *edge = node->Outgoing;
// set up edge constraint in aux solver
void RPFP::AddEdgeToSolver(Edge *edge){
if(!edge->dual.null())
aux_solver.add(edge->dual);
for(unsigned i = 0; i < edge->constraints.size(); i++){
expr tl = edge->constraints[i];
aux_solver.add(tl);
}
GreedyReduce(aux_solver,conjuncts);
}
void RPFP::InterpolateByCases(Node *root, Node *node){
aux_solver.push();
AddEdgeToSolver(node->Outgoing);
node->Annotation.SetEmpty();
hash_set<ast> *core = new hash_set<ast>;
core->insert(node->Outgoing->dual);
while(1){
aux_solver.push();
aux_solver.add(!GetAnnotation(node));
if(aux_solver.check() == unsat){
aux_solver.pop(1);
break;
}
dualModel = aux_solver.get_model();
aux_solver.pop(1);
Push();
FixCurrentStateFull(node->Outgoing);
ConstrainEdgeLocalized(node->Outgoing,!GetAnnotation(node));
check_result foo = Check(root);
if(foo != unsat)
throw "should be unsat";
AddToProofCore(*core);
Transformer old_annot = node->Annotation;
SolveSingleNode(root,node);
Pop(1);
node->Annotation.UnionWith(old_annot);
}
if(proof_core)
delete proof_core; // shouldn't happen
proof_core = core;
aux_solver.pop(1);
}
void RPFP::Generalize(Node *root, Node *node){
aux_solver.push();
AddEdgeToSolver(node->Outgoing);
expr fmla = GetAnnotation(node);
std::vector<expr> conjuncts;
CollectConjuncts(fmla,conjuncts,false);
GreedyReduce(aux_solver,conjuncts); // try to remove conjuncts one at a tme
aux_solver.pop(1);
NegateLits(conjuncts);
SetAnnotation(node,SimplifyOr(conjuncts));
@ -1887,12 +2035,26 @@ namespace Duality {
(*it)->dual = expr(ctx,NULL);
for(std::list<Node *>::iterator it = back.nodes.begin(), en = back.nodes.end(); it != en; ++it)
(*it)->dual = expr(ctx,NULL);
for(std::list<Edge *>::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it)
(*it)->constraints.pop_back();
for(std::list<std::pair<Edge *,Term> >::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it)
(*it).first->constraints.pop_back();
stack.pop_back();
}
}
/** Erase the proof by performing a Pop, Push and re-assertion of
all the popped constraints */
void RPFP::PopPush(){
slvr.pop(1);
slvr.push();
stack_entry &back = stack.back();
for(std::list<Edge *>::iterator it = back.edges.begin(), en = back.edges.end(); it != en; ++it)
slvr.add((*it)->dual);
for(std::list<Node *>::iterator it = back.nodes.begin(), en = back.nodes.end(); it != en; ++it)
slvr.add((*it)->dual);
for(std::list<std::pair<Edge *,Term> >::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it)
slvr.add((*it).second);
}
@ -2325,13 +2487,17 @@ namespace Duality {
}
void RPFP::AddToProofCore(hash_set<ast> &core){
std::vector<expr> assumps;
slvr.get_proof().get_assumptions(assumps);
for(unsigned i = 0; i < assumps.size(); i++)
core.insert(assumps[i]);
}
void RPFP::ComputeProofCore(){
if(!proof_core){
std::vector<expr> assumps;
slvr.get_proof().get_assumptions(assumps);
proof_core = new hash_set<ast>;
for(unsigned i = 0; i < assumps.size(); i++)
proof_core->insert(assumps[i]);
AddToProofCore(*proof_core);
}
}

View file

@ -1754,12 +1754,14 @@ namespace Duality {
for(unsigned i = 0; i < expansions.size(); i++){
Node *node = expansions[i];
tree->SolveSingleNode(top,node);
tree->Generalize(node);
if(expansions.size() == 1 && NodeTooComplicated(node))
SimplifyNode(node);
tree->Generalize(top,node);
if(RecordUpdate(node))
update_count++;
}
if(update_count == 0)
std::cout << "backtracked without learning\n";
reporter->Message("backtracked without learning");
}
tree->ComputeProofCore(); // need to compute the proof core before popping solver
while(1) {
@ -1816,6 +1818,16 @@ namespace Duality {
}
}
bool NodeTooComplicated(Node *node){
return tree->CountOperators(node->Annotation.Formula) > 5;
}
void SimplifyNode(Node *node){
// have to destroy the old proof to get a new interpolant
tree->PopPush();
tree->InterpolateByCases(top,node);
}
bool LevelUsedInProof(unsigned level){
std::vector<Node *> &expansions = stack[level].expansions;
for(unsigned i = 0; i < expansions.size(); i++)

View file

@ -34,8 +34,12 @@ namespace Duality {
p.set_bool("proof", true); // this is currently useless
p.set_bool("model", true);
p.set_bool("unsat_core", true);
p.set_bool("mbqi",true);
p.set_str("mbqi.id","itp"); // use mbqi for quantifiers in interpolants
p.set_uint("mbqi.max_iterations",1); // use mbqi for quantifiers in interpolants
scoped_ptr<solver_factory> sf = mk_smt_solver_factory();
m_solver = (*sf)(m(), p, true, true, true, ::symbol::null);
m_solver->updt_params(p); // why do we have to do this?
canceled = false;
}

View file

@ -413,6 +413,7 @@ namespace Duality {
expr operator()(unsigned n, expr const * args) const;
expr operator()(const std::vector<expr> &args) const;
expr operator()() const;
expr operator()(expr const & a) const;
expr operator()(int a) const;
expr operator()(expr const & a1, expr const & a2) const;
@ -1184,6 +1185,9 @@ namespace Duality {
inline expr func_decl::operator()(const std::vector<expr> &args) const {
return operator()(args.size(),&args[0]);
}
inline expr func_decl::operator()() const {
return operator()(0,0);
}
inline expr func_decl::operator()(expr const & a) const {
return operator()(1,&a);
}