diff --git a/src/duality/duality.h b/src/duality/duality.h index e35c97b50..e7516c1db 100755 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -746,6 +746,10 @@ protected: struct bad_format { }; + // thrown on internal error + struct Bad { + }; + /** Pop a scope (see Push). Note, you cannot pop axioms. */ void Pop(int num_scopes); diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index f3deee225..7d3ddda7e 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -2954,6 +2954,8 @@ namespace Duality { } } + static int by_case_counter = 0; + void RPFP::InterpolateByCases(Node *root, Node *node){ timer_start("InterpolateByCases"); bool axioms_added = false; @@ -2968,6 +2970,7 @@ namespace Duality { hash_set *core = new hash_set; core->insert(node->Outgoing->dual); while(1){ + by_case_counter++; is.push(); expr annot = !GetAnnotation(node); is.add(annot); @@ -3009,6 +3012,23 @@ namespace Duality { for(unsigned i = 0; i < axioms_to_add.size(); i++) is.add(axioms_to_add[i]); +#define TEST_BAD +#ifdef TEST_BAD + { + static int bad_count = 0, num_bads = 1; + if(bad_count >= num_bads){ + bad_count = 0; + num_bads = num_bads * 2; + Pop(1); + is.pop(1); + delete core; + timer_stop("InterpolateByCases"); + throw Bad(); + } + bad_count++; + } +#endif + if(node->Annotation.IsEmpty()){ if(!axioms_added){ // add the axioms in the off chance they are useful @@ -3018,12 +3038,48 @@ namespace Duality { axioms_added = true; } else { +#ifdef KILL_ON_BAD_INTERPOLANT std::cout << "bad in InterpolateByCase -- core:\n"; +#if 0 std::vector assumps; slvr().get_proof().get_assumptions(assumps); for(unsigned i = 0; i < assumps.size(); i++) assumps[i].show(); +#endif + std::cout << "checking for inconsistency\n"; + std::cout << "model:\n"; + is.get_model().show(); + expr impl = is.get_implicant(); + std::vector conjuncts; + CollectConjuncts(impl,conjuncts,true); + std::cout << "impl:\n"; + for(unsigned i = 0; i < conjuncts.size(); i++) + conjuncts[i].show(); + std::cout << "annot:\n"; + annot.show(); + is.add(annot); + for(unsigned i = 0; i < conjuncts.size(); i++) + is.add(conjuncts[i]); + if(is.check() == unsat){ + std::cout << "inconsistent!\n"; + std::vector is_assumps; + is.aux_solver.get_proof().get_assumptions(is_assumps); + std::cout << "core:\n"; + for(unsigned i = 0; i < is_assumps.size(); i++) + is_assumps[i].show(); + } + else { + std::cout << "consistent!\n"; + is.aux_solver.print("should_be_inconsistent.smt2"); + } + std::cout << "by_case_counter = " << by_case_counter << "\n"; throw "ack!"; +#endif + Pop(1); + is.pop(1); + delete core; + timer_stop("InterpolateByCases"); + throw Bad(); } } Pop(1); diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index d59309c00..9c910a2e7 100755 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -2078,7 +2078,24 @@ namespace Duality { stack.push_back(stack_entry()); } + struct DoRestart {}; + virtual bool Build(){ + while (true) { + try { + return BuildMain(); + } + catch (const DoRestart &) { + // clear the statck and try again + updated_nodes.clear(); + while(stack.size() > 1) + PopLevel(); + reporter->Message("restarted"); + } + } + } + + bool BuildMain(){ stack.back().level = tree->slvr().get_scope_level(); bool was_sat = true; @@ -2110,11 +2127,17 @@ namespace Duality { #ifdef NO_GENERALIZE node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); #else - if(expansions.size() == 1 && NodeTooComplicated(node)) - SimplifyNode(node); - else - node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); - Generalize(node); + try { + if(expansions.size() == 1 && NodeTooComplicated(node)) + SimplifyNode(node); + else + node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); + Generalize(node); + } + catch(const RPFP::Bad &){ + // bad interpolants can get us here + throw DoRestart(); + } #endif if(RecordUpdate(node)) update_count++; @@ -2134,28 +2157,8 @@ namespace Duality { tree->ComputeProofCore(); // need to compute the proof core before popping solver bool propagated = false; while(1) { - std::vector &expansions = stack.back().expansions; bool prev_level_used = LevelUsedInProof(stack.size()-2); // need to compute this before pop - tree->Pop(1); - hash_set leaves_to_remove; - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - // if(node != top) - // tree->ConstrainParent(node->Incoming[0],node); - std::vector &cs = node->Outgoing->Children; - for(unsigned i = 0; i < cs.size(); i++){ - leaves_to_remove.insert(cs[i]); - UnmapNode(cs[i]); - if(std::find(updated_nodes.begin(),updated_nodes.end(),cs[i]) != updated_nodes.end()) - throw "help!"; - } - } - RemoveLeaves(leaves_to_remove); // have to do this before actually deleting the children - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - RemoveExpansion(node); - } - stack.pop_back(); + PopLevel(); if(stack.size() == 1)break; if(prev_level_used){ Node *node = stack.back().expansions[0]; @@ -2213,6 +2216,30 @@ namespace Duality { } } + void PopLevel(){ + std::vector &expansions = stack.back().expansions; + tree->Pop(1); + hash_set leaves_to_remove; + for(unsigned i = 0; i < expansions.size(); i++){ + Node *node = expansions[i]; + // if(node != top) + // tree->ConstrainParent(node->Incoming[0],node); + std::vector &cs = node->Outgoing->Children; + for(unsigned i = 0; i < cs.size(); i++){ + leaves_to_remove.insert(cs[i]); + UnmapNode(cs[i]); + if(std::find(updated_nodes.begin(),updated_nodes.end(),cs[i]) != updated_nodes.end()) + throw "help!"; + } + } + RemoveLeaves(leaves_to_remove); // have to do this before actually deleting the children + for(unsigned i = 0; i < expansions.size(); i++){ + Node *node = expansions[i]; + RemoveExpansion(node); + } + stack.pop_back(); + } + bool NodeTooComplicated(Node *node){ int ops = tree->CountOperators(node->Annotation.Formula); if(ops > 10) return true; @@ -2224,7 +2251,13 @@ namespace Duality { // have to destroy the old proof to get a new interpolant timer_start("SimplifyNode"); tree->PopPush(); - tree->InterpolateByCases(top,node); + try { + tree->InterpolateByCases(top,node); + } + catch(const RPFP::Bad&){ + timer_stop("SimplifyNode"); + throw RPFP::Bad(); + } timer_stop("SimplifyNode"); }