3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-26 13:06:05 +00:00

speeding up Generalize and adding Lazy Propagation

This commit is contained in:
Ken McMillan 2013-12-21 16:54:35 -08:00
parent 48e10a9e2d
commit c98b853917
7 changed files with 491 additions and 51 deletions

View file

@ -519,6 +519,20 @@ namespace Duality {
const expr &lit = args[i];
expr atom, val;
if(IsLiteral(lit,atom,val)){
if(atom.is_app() && atom.decl().get_decl_kind() == Equal)
if(pol ? eq(val,ctx.bool_val(true)) : eq(val,ctx.bool_val(false))){
expr lhs = atom.arg(0), rhs = atom.arg(1);
if(lhs.is_numeral())
std::swap(lhs,rhs);
if(rhs.is_numeral() && lhs.is_app()){
for(unsigned j = 0; j < args.size(); j++)
if(j != i){
smemo.clear();
smemo[lhs] = rhs;
args[j] = SubstRec(smemo,args[j]);
}
}
}
for(unsigned j = 0; j < args.size(); j++)
if(j != i){
smemo.clear();
@ -711,6 +725,39 @@ namespace Duality {
#endif
expr RPFP::GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox)
{
if (e->dual.null()) {
timer_start("ReducedDualEdge");
e->dual = ReducedDualEdge(e);
timer_stop("ReducedDualEdge");
timer_start("getting children");
if(with_children)
for(unsigned i = 0; i < e->Children.size(); i++)
e->dual = e->dual && GetAnnotation(e->Children[i]);
if(underapprox){
std::vector<expr> cus(e->Children.size());
for(unsigned i = 0; i < e->Children.size(); i++)
cus[i] = !UnderapproxFlag(e->Children[i]) || GetUnderapprox(e->Children[i]);
expr cnst = conjoin(cus);
e->dual = e->dual && cnst;
}
timer_stop("getting children");
timer_start("Persisting");
std::list<stack_entry>::reverse_iterator it = stack.rbegin();
for(int i = 0; i < persist && it != stack.rend(); i++)
it++;
if(it != stack.rend())
it->edges.push_back(e);
timer_stop("Persisting");
//Console.WriteLine("{0}", cnst);
}
return e->dual;
timer_start("solver add");
slvr.add(e->dual);
timer_stop("solver add");
}
/** For incremental solving, asserts the constraint associated
* with this edge in the SMT context. If this edge is removed,
* you must pop the context accordingly. The second argument is
@ -732,41 +779,40 @@ namespace Duality {
{
if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty()))
return;
if (e->dual.null())
{
timer_start("ReducedDualEdge");
e->dual = ReducedDualEdge(e);
timer_stop("ReducedDualEdge");
timer_start("getting children");
if(with_children)
for(unsigned i = 0; i < e->Children.size(); i++)
e->dual = e->dual && GetAnnotation(e->Children[i]);
if(underapprox){
std::vector<expr> cus(e->Children.size());
for(unsigned i = 0; i < e->Children.size(); i++)
cus[i] = !UnderapproxFlag(e->Children[i]) || GetUnderapprox(e->Children[i]);
expr cnst = conjoin(cus);
e->dual = e->dual && cnst;
}
timer_stop("getting children");
timer_start("Persisting");
std::list<stack_entry>::reverse_iterator it = stack.rbegin();
for(int i = 0; i < persist && it != stack.rend(); i++)
it++;
if(it != stack.rend())
it->edges.push_back(e);
#if 0
if(persist != 0)
Z3_persist_ast(ctx,e->dual,persist);
#endif
timer_stop("Persisting");
//Console.WriteLine("{0}", cnst);
}
expr fmla = GetEdgeFormula(e, persist, with_children, underapprox);
timer_start("solver add");
slvr.add(e->dual);
timer_stop("solver add");
}
// caching verion of above
void RPFP_caching::AssertEdgeCache(Edge *e, std::vector<Term> &lits, bool with_children){
if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty()))
return;
expr fmla = GetEdgeFormula(e, 0, with_children, false);
GetAssumptionLits(fmla,lits);
}
void RPFP_caching::GetAssumptionLits(const expr &fmla, std::vector<expr> &lits, hash_map<ast,expr> *opt_map){
std::vector<expr> conjs;
CollectConjuncts(fmla,conjs);
for(unsigned i = 0; i < conjs.size(); i++){
const expr &conj = conjs[i];
std::pair<ast,Term> foo(conj,expr(ctx));
std::pair<hash_map<ast,Term>::iterator, bool> bar = AssumptionLits.insert(foo);
Term &res = bar.first->second;
if(bar.second){
func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort());
res = pred();
slvr.add(ctx.make(Implies,res,conj));
// std::cout << res << ": " << conj << "\n";
}
if(opt_map)
(*opt_map)[res] = conj;
lits.push_back(res);
}
}
void RPFP::ConstrainParent(Edge *parent, Node *child){
ConstrainEdgeLocalized(parent,GetAnnotation(child));
}
@ -786,6 +832,53 @@ namespace Duality {
}
}
// caching version of above
void RPFP_caching::AssertNodeCache(Node *n, std::vector<Term> lits){
if (n->dual.null())
{
n->dual = GetUpperBound(n);
stack.back().nodes.push_back(n);
GetAssumptionLits(n->dual,lits);
}
}
/** Clone another RPFP into this one, keeping a map */
void RPFP_caching::Clone(RPFP *other){
for(unsigned i = 0; i < other->nodes.size(); i++)
NodeCloneMap[other->nodes[i]] = CloneNode(other->nodes[i]);
for(unsigned i = 0; i < other->edges.size(); i++){
Edge *edge = other->edges[i];
std::vector<Node *> cs;
for(unsigned j = 0; j < edge->Children.size(); j++)
// cs.push_back(NodeCloneMap[edge->Children[j]]);
cs.push_back(CloneNode(edge->Children[j]));
EdgeCloneMap[edge] = CreateEdge(NodeCloneMap[edge->Parent],edge->F,cs);
}
}
/** Get the clone of a node */
RPFP::Node *RPFP_caching::GetNodeClone(Node *other_node){
return NodeCloneMap[other_node];
}
/** Get the clone of an edge */
RPFP::Edge *RPFP_caching::GetEdgeClone(Edge *other_edge){
return EdgeCloneMap[other_edge];
}
/** check assumption lits, and return core */
check_result RPFP_caching::CheckCore(const std::vector<Term> &assumps, std::vector<Term> &core){
core.resize(assumps.size());
unsigned core_size;
check_result res = slvr.check(assumps.size(),(expr *)&assumps[0],&core_size,&core[0]);
if(res == unsat)
core.resize(core_size);
else
core.clear();
return res;
}
/** Assert a constraint on an edge in the SMT context.
*/
@ -970,6 +1063,7 @@ namespace Duality {
check_result RPFP::Check(Node *root, std::vector<Node *> underapproxes, std::vector<Node *> *underapprox_core )
{
timer_start("Check");
ClearProofCore();
// if (dualModel != null) dualModel.Dispose();
check_result res;
@ -1002,6 +1096,7 @@ namespace Duality {
// check_result temp = slvr.check();
}
dualModel = slvr.get_model();
timer_stop("Check");
return res;
}
@ -1927,10 +2022,14 @@ namespace Duality {
for(int i = 0; i < num_args; i++)
CollectConjuncts(f.arg(i),lits,false);
}
else if(pos)
lits.push_back(f);
else
lits.push_back(!f);
else if(pos){
if(!eq(f,ctx.bool_val(true)))
lits.push_back(f);
}
else {
if(!eq(f,ctx.bool_val(false)))
lits.push_back(!f);
}
}
struct TermLt {
@ -2253,6 +2352,45 @@ namespace Duality {
}
}
void RPFP_caching::FilterCore(std::vector<expr> &core, std::vector<expr> &full_core){
hash_set<ast> core_set;
std::copy(full_core.begin(),full_core.end(),std::inserter(core_set,core_set.begin()));
std::vector<expr> new_core;
for(unsigned i = 0; i < core.size(); i++)
if(core_set.find(core[i]) != core_set.end())
new_core.push_back(core[i]);
core.swap(new_core);
}
void RPFP_caching::GreedyReduceCache(std::vector<expr> &assumps, std::vector<expr> &core){
std::vector<expr> lits = assumps, full_core;
std::copy(core.begin(),core.end(),std::inserter(lits,lits.end()));
// verify
check_result res = CheckCore(lits,full_core);
if(res != unsat)
throw "should be unsat";
FilterCore(core,full_core);
std::vector<expr> dummy;
if(CheckCore(full_core,dummy) != unsat)
throw "should be unsat";
for(unsigned i = 0; i < core.size(); ){
expr temp = core[i];
std::swap(core[i],core.back());
core.pop_back();
lits.resize(assumps.size());
std::copy(core.begin(),core.end(),std::inserter(lits,lits.end()));
res = CheckCore(lits,full_core);
if(res != unsat){
core.push_back(temp);
std::swap(core[i],core.back());
i++;
}
}
}
expr RPFP::NegateLit(const expr &f){
if(f.is_app() && f.decl().get_decl_kind() == Not)
return f.arg(0);
@ -2278,6 +2416,14 @@ namespace Duality {
return ctx.make(Or,lits);
}
expr RPFP::SimplifyAnd(std::vector<expr> &lits){
if(lits.size() == 0)
return ctx.bool_val(true);
if(lits.size() == 1)
return lits[0];
return ctx.make(And,lits);
}
// set up edge constraint in aux solver
void RPFP::AddEdgeToSolver(Edge *edge){
if(!edge->dual.null())
@ -2321,7 +2467,7 @@ namespace Duality {
std::vector<expr> case_lits;
itp = StrengthenFormulaByCaseSplitting(itp, case_lits);
SetAnnotation(node,itp);
node->Annotation.Formula.simplify();
node->Annotation.Formula = node->Annotation.Formula.simplify();
}
if(node->Annotation.IsEmpty()){
@ -2330,6 +2476,7 @@ namespace Duality {
const std::vector<expr> &theory = ls->get_axioms();
for(unsigned i = 0; i < theory.size(); i++)
aux_solver.add(theory[i]);
axioms_added = true;
}
else {
std::cout << "bad in InterpolateByCase -- core:\n";
@ -2350,6 +2497,7 @@ namespace Duality {
}
void RPFP::Generalize(Node *root, Node *node){
timer_start("Generalize");
aux_solver.push();
AddEdgeToSolver(node->Outgoing);
expr fmla = GetAnnotation(node);
@ -2359,8 +2507,103 @@ namespace Duality {
aux_solver.pop(1);
NegateLits(conjuncts);
SetAnnotation(node,SimplifyOr(conjuncts));
timer_stop("Generalize");
}
// caching version of above
void RPFP_caching::GeneralizeCache(Edge *edge){
timer_start("Generalize");
Node *node = edge->Parent;
std::vector<expr> assumps, core, conjuncts;
AssertEdgeCache(edge,assumps);
for(unsigned i = 0; i < edge->Children.size(); i++){
expr ass = GetAnnotation(edge->Children[i]);
std::vector<expr> clauses;
CollectConjuncts(ass.arg(1),clauses);
for(unsigned j = 0; j < clauses.size(); j++)
GetAssumptionLits(ass.arg(0) || clauses[j],assumps);
}
expr fmla = GetAnnotation(node);
assumps.push_back(fmla.arg(0).arg(0));
std::vector<expr> lits;
CollectConjuncts(!fmla.arg(1),lits);
#if 0
for(unsigned i = 0; i < lits.size(); i++){
const expr &lit = lits[i];
if(lit.is_app() && lit.decl().get_decl_kind() == Equal){
lits[i] = ctx.make(Leq,lit.arg(0),lit.arg(1));
lits.push_back(ctx.make(Leq,lit.arg(1),lit.arg(0)));
}
}
#endif
hash_map<ast,expr> lit_map;
for(unsigned i = 0; i < lits.size(); i++)
GetAssumptionLits(lits[i],core,&lit_map);
GreedyReduceCache(assumps,core);
for(unsigned i = 0; i < core.size(); i++)
conjuncts.push_back(lit_map[core[i]]);
NegateLits(conjuncts);
SetAnnotation(node,SimplifyOr(conjuncts));
timer_stop("Generalize");
}
// caching version of above
bool RPFP_caching::PropagateCache(Edge *edge){
timer_start("PropagateCache");
bool some = false;
{
std::vector<expr> candidates, skip;
Node *node = edge->Parent;
CollectConjuncts(node->Annotation.Formula,skip);
for(unsigned i = 0; i < edge->Children.size(); i++){
Node *child = edge->Children[i];
if(child->map == node->map){
CollectConjuncts(child->Annotation.Formula,candidates);
break;
}
}
if(candidates.empty()) goto done;
hash_set<ast> skip_set;
std::copy(skip.begin(),skip.end(),std::inserter(skip_set,skip_set.begin()));
std::vector<expr> new_candidates;
for(unsigned i = 0; i < candidates.size(); i++)
if(skip_set.find(candidates[i]) == skip_set.end())
new_candidates.push_back(candidates[i]);
candidates.swap(new_candidates);
if(candidates.empty()) goto done;
std::vector<expr> assumps, core, conjuncts;
AssertEdgeCache(edge,assumps);
for(unsigned i = 0; i < edge->Children.size(); i++){
expr ass = GetAnnotation(edge->Children[i]);
std::vector<expr> clauses;
CollectConjuncts(ass.arg(1),clauses);
for(unsigned j = 0; j < clauses.size(); j++)
GetAssumptionLits(ass.arg(0) || clauses[j],assumps);
}
for(unsigned i = 0; i < candidates.size(); i++){
unsigned old_size = assumps.size();
node->Annotation.Formula = candidates[i];
expr fmla = GetAnnotation(node);
assumps.push_back(fmla.arg(0).arg(0));
GetAssumptionLits(!fmla.arg(1),assumps);
std::vector<expr> full_core;
check_result res = CheckCore(assumps,full_core);
if(res == unsat)
conjuncts.push_back(candidates[i]);
assumps.resize(old_size);
}
if(conjuncts.empty())
goto done;
SetAnnotation(node,SimplifyAnd(conjuncts));
some = true;
}
done:
timer_stop("PropagateCache");
return some;
}
/** Push a scope. Assertions made after Push can be undone by Pop. */
void RPFP::Push()