//each vtree node is associated with a set of litsets (clauses or terms) //the totality of these litsets represent an fnf (cnf or dnf) //returns an sdd which is equivalent to the cnf/dnf associated with vtree SddNode* apply_vtree_auto(Vtree* vtree, BoolOp op, SddManager* manager) { //get litsets associated with vtree node //do this first as vtree root may be changed by dynamic vtree search LitSet** litsets = DATA(vtree,litsets); SddSize litset_count = DATA(vtree,litset_count); sort_litsets_by_lca(litsets,litset_count,manager); SddNode* node; if(sdd_vtree_is_leaf(vtree)) node = ONE(manager,op); else { SddNode* l_node = apply_vtree_auto(sdd_vtree_left(vtree),op,manager); sdd_ref(l_node,manager); SddNode* r_node = apply_vtree_auto(sdd_vtree_right(vtree),op,manager); sdd_deref(l_node,manager); node = sdd_apply(l_node,r_node,op,manager); } while(litset_count--) { //compile and integrate litset sdd_ref(node,manager); SddNode* litset = apply_litset_auto(*litsets++,manager); //may gc node sdd_deref(node,manager); node = sdd_apply(litset,node,op,manager); //recompute lcas of remaining clauses and sort again sort_litsets_by_lca(litsets,litset_count,manager); } return node; }
int main(int argc, char** argv) { // set up vtree and manager SddLiteral var_count = 4; const char* type = "right"; Vtree* vtree = sdd_vtree_new(var_count,type); SddManager* manager = sdd_manager_new(vtree); // construct the term X_1 ^ X_2 ^ X_3 ^ X_4 SddNode* alpha = sdd_manager_literal(1,manager); alpha = sdd_conjoin(alpha,sdd_manager_literal(2,manager),manager); alpha = sdd_conjoin(alpha,sdd_manager_literal(3,manager),manager); alpha = sdd_conjoin(alpha,sdd_manager_literal(4,manager),manager); // construct the term ~X_1 ^ X_2 ^ X_3 ^ X_4 SddNode* beta = sdd_manager_literal(-1,manager); beta = sdd_conjoin(beta,sdd_manager_literal(2,manager),manager); beta = sdd_conjoin(beta,sdd_manager_literal(3,manager),manager); beta = sdd_conjoin(beta,sdd_manager_literal(4,manager),manager); // construct the term ~X_1 ^ ~X_2 ^ X_3 ^ X_4 SddNode* gamma = sdd_manager_literal(-1,manager); gamma = sdd_conjoin(gamma,sdd_manager_literal(-2,manager),manager); gamma = sdd_conjoin(gamma,sdd_manager_literal(3,manager),manager); gamma = sdd_conjoin(gamma,sdd_manager_literal(4,manager),manager); printf("== before referencing:\n"); printf(" live sdd size = %zu\n", sdd_manager_live_size(manager)); printf(" dead sdd size = %zu\n", sdd_manager_dead_size(manager)); // ref SDDs so that they are not garbage collected sdd_ref(alpha,manager); sdd_ref(beta,manager); sdd_ref(gamma,manager); printf("== after referencing:\n"); printf(" live sdd size = %zu\n", sdd_manager_live_size(manager)); printf(" dead sdd size = %zu\n", sdd_manager_dead_size(manager)); // garbage collect sdd_manager_garbage_collect(manager); printf("== after garbage collection:\n"); printf(" live sdd size = %zu\n", sdd_manager_live_size(manager)); printf(" dead sdd size = %zu\n", sdd_manager_dead_size(manager)); sdd_deref(alpha,manager); sdd_deref(beta,manager); sdd_deref(gamma,manager); printf("saving vtree & shared sdd ...\n"); sdd_vtree_save_as_dot("output/shared-vtree.dot",vtree); sdd_shared_save_as_dot("output/shared.dot",manager); sdd_vtree_free(vtree); sdd_manager_free(manager); return 0; }
SddNode* Prover::branchToSDD(std::vector<SddLiteral> variables, SddManager* m) { SddNode* alpha = sdd_manager_true(m); SddNode* tmp; for (SddLiteral i: variables) { alpha = sdd_conjoin(tmp = alpha, sdd_manager_literal(i,m),m); sdd_ref(alpha,m); sdd_deref(tmp,m); } sdd_deref(alpha,m); return alpha; }
SddNode* S4Prover::refineSdd(std::vector<SddLiteral> literals, SddNode* oldSdd, SddManager* m) { SddNode* tmp; SddNode* newSdd = sdd_manager_false(m); for (SddLiteral lit : literals) { newSdd = sdd_disjoin(tmp = newSdd, sdd_manager_literal(-lit,m),m); sdd_ref(newSdd,m); sdd_deref(tmp,m); } newSdd = sdd_conjoin(oldSdd,tmp = newSdd,m); sdd_deref(tmp,m); return newSdd; }
//each vtree node is associated with a set of litsets (clauses or terms) //the totality of these litsets represent an fnf (cnf or dnf) //returns an sdd which is equivalent to the cnf/dnf associated with vtree SddNode* apply_vtree_manual(Vtree* vtree, BoolOp op, SddManager* manager) { SddNode* base; if(sdd_vtree_is_leaf(vtree)) base = ONE(manager,op); else { SddNode* l_node = apply_vtree_manual(sdd_vtree_left(vtree),op,manager); SddNode* r_node = apply_vtree_manual(sdd_vtree_right(vtree),op,manager); base = sdd_apply_in_vtree(l_node,r_node,op,vtree,manager); } SddSize litset_count = DATA(vtree,litset_count); if(litset_count==0) return base; //no clauses/terms stored at vtree node //apply litsets may change root of vtree due to vtree search Vtree** vtree_loc = sdd_vtree_location(vtree,manager); SddNode* node = apply_litsets_manual(base,op,vtree,manager); vtree = *vtree_loc; //root may have changed SddManagerOptions* options = sdd_manager_options(manager); if(options->vtree_search_mode==2) { sdd_ref(node,manager); //to SWITCH-TO-LIBRARY-SEARCH, comment in the next line, comment out the one after vtree_search(vtree,manager); // sdd_vtree_minimize(vtree,manager); //library's version of vtree search algorithm sdd_deref(node,manager); } return node; }
//convert the clauses/terms associated with vtree into sdds and combine them with base using op SddNode* apply_litsets_manual(SddNode* base, BoolOp op, Vtree* vtree, SddManager* manager) { //get litsets associated with vtree node LitSet** litsets = DATA(vtree,litsets); SddSize litset_count = DATA(vtree,litset_count); assert(litset_count!=0); sort_litsets_by_lca(litsets,litset_count,manager); SddNode* result = base; sdd_ref(result,manager); //must be done after referencing SddSize prev_size = sdd_vtree_live_size(vtree); SddManagerOptions* options = sdd_manager_options(manager); while(litset_count--) { //compile and integrate litset SddNode* node = apply_litset_manual(*litsets++,vtree,manager); sdd_deref(result,manager); result = sdd_apply_in_vtree(node,result,op,vtree,manager); sdd_ref(result,manager); if(options->vtree_search_mode==2) { SddSize cur_size = sdd_vtree_live_size(vtree); //after integrating last litset if(cur_size > prev_size*options->vtree_search_threshold) { //to SWITCH-TO-LIBRARY-SEARCH, comment in the next line, comment out the one after vtree = vtree_search(vtree,manager); // root of vtree may have changed // vtree = sdd_vtree_minimize(vtree,manager); //library's version of vtree search algorithm prev_size = sdd_vtree_live_size(vtree); //since last call to dynamic vtree //recompute lcas of remaining clauses and sort again sort_litsets_by_lca(litsets,litset_count,manager); } } sdd_vtree_garbage_collect_if(options->gc_threshold,vtree,manager); } sdd_deref(result,manager); return result; }
bool S4Prover::isSatisfiable(SddNode* alpha, SddManager* m, std::unordered_set<SddLiteral> permVars, SddNode* permSdd, std::unordered_set<SddNode*,SddHasher>& assumedSatSdds , std::unordered_set<SddLiteral>& responsibleVars) { //Match against cache if (satCache.count(alpha) == 1) { return true; } //Base cases if (sdd_node_is_true(alpha)) { return true; } if (sdd_node_is_false(alpha)) { return false; } //Scrape off a single satisfying set, corresponding to a single open tableaux branch. std::vector<SddLiteral> branch = getOpenBranch(alpha, std::vector<SddLiteral>()); SddNode* branchSdd = branchToSDD(branch,m); sdd_ref(branchSdd,m); /*std::cout << "BRANCH\n\n"; for (SddLiteral i : branch) { if (i < 0) std::cout << "~" << *literalsToAtoms[-i] << "\n\n"; else std::cout << *literalsToAtoms[i] << "\n\n"; } std::cout << "BRANCH END\n\n";*/ //Extract all modal atoms from the branch. std::vector<SddLiteral> boxes; std::vector<SddLiteral> negBoxes; if (extractModals(branch,boxes,negBoxes) == 0) { return true; }; //Checks for new boxed variables SddNode* tmp; std::unordered_set<SddLiteral> newPermVars = permVars; std::vector<SddLiteral> unboxed; SddNode* postUnboxingBranch = sdd_conjoin(sdd_manager_true(m),branchSdd,m); sdd_ref(postUnboxingBranch,m); SddNode* newPermSdd = sdd_conjoin(sdd_manager_true(m),permSdd,m); sdd_ref(newPermSdd,m); for (SddLiteral i : boxes) { if (newPermVars.count(i) == 0) { unboxed.push_back(i); newPermVars.insert(i); postUnboxingBranch = sdd_conjoin(tmp = postUnboxingBranch, compiler::KtoSDD(&literalsToAtoms[i]->getleft(),m),m); sdd_deref(tmp,m); sdd_ref(postUnboxingBranch,m); newPermSdd = sdd_conjoin(tmp = newPermSdd, compiler::KtoSDD(&literalsToAtoms[i]->getleft(),m),m); sdd_deref(tmp,m); sdd_ref(newPermSdd,m); newPermSdd = sdd_conjoin(tmp = newPermSdd, compiler::KtoSDD(literalsToAtoms[i],m),m); sdd_deref(tmp,m); sdd_ref(newPermSdd,m); //If becomes false while unboxing, recurse. if (sdd_node_is_false(postUnboxingBranch)) { //Determine minimal set of unboxed variables std::vector<SddLiteral> minLits; minLits.push_back(i); responsibleVars.insert(i); std::vector<SddLiteral>::iterator endIt = --(unboxed.end()); SddNode* minimalSdd = sdd_conjoin(compiler::KtoSDD(&literalsToAtoms[i]->getleft(),m),branchSdd,m); sdd_ref(minimalSdd,m); SddNode* minBoxVarsSdd = sdd_conjoin(compiler::KtoSDD(&literalsToAtoms[i]->getleft(),m),sdd_manager_true(m),m); sdd_ref(minBoxVarsSdd,m); while (true) { sdd_deref(postUnboxingBranch,m); postUnboxingBranch = sdd_conjoin(minimalSdd, sdd_manager_true(m), m); sdd_ref(postUnboxingBranch,m); if (sdd_node_is_false(postUnboxingBranch)) break; //Last one added made it false for (std::vector<SddLiteral>::iterator v = unboxed.begin(); v != endIt; ++v) { postUnboxingBranch = sdd_conjoin(tmp = postUnboxingBranch, compiler::KtoSDD(&literalsToAtoms[*v]->getleft(),m),m); sdd_deref(tmp,m); sdd_ref(postUnboxingBranch,m); if (sdd_node_is_false(postUnboxingBranch)) { //Last one added made it false minimalSdd = sdd_conjoin(tmp = minimalSdd, compiler::KtoSDD(&literalsToAtoms[*v]->getleft(),m),m); sdd_deref(tmp,m); sdd_ref(minimalSdd,m); minBoxVarsSdd = sdd_conjoin(tmp = minBoxVarsSdd,compiler::KtoSDD(&literalsToAtoms[*v]->getleft(),m),m); sdd_deref(tmp,m); sdd_ref(minBoxVarsSdd,m); minLits.push_back(*v); responsibleVars.insert(*v); endIt = v; break; } } } // Determine minimal set of branch variables together with unboxed variables std::vector<SddLiteral>::iterator BendIt = branch.end(); sdd_deref(minimalSdd,m); minimalSdd = sdd_conjoin(sdd_manager_true(m),minBoxVarsSdd,m); sdd_ref(minimalSdd,m); while (true) { sdd_deref(minBoxVarsSdd,m); minBoxVarsSdd = sdd_conjoin(minimalSdd, sdd_manager_true(m), m); sdd_ref(minBoxVarsSdd,m); if (sdd_node_is_false(minBoxVarsSdd)) break; //Last one added made it false for (std::vector<SddLiteral>::iterator v = branch.begin(); v != BendIt; ++v) { minBoxVarsSdd = sdd_conjoin(tmp = minBoxVarsSdd, sdd_manager_literal(*v,m), m); sdd_deref(tmp,m); sdd_ref(minBoxVarsSdd,m); if (sdd_node_is_false(minBoxVarsSdd)) { //Last one added made it false minimalSdd = sdd_conjoin(tmp = minimalSdd, sdd_manager_literal(*v,m),m); sdd_deref(tmp,m); sdd_ref(minimalSdd,m); minLits.push_back(*v); responsibleVars.insert(*v); BendIt = v; break; } } } sdd_deref(minimalSdd,m); sdd_deref(postUnboxingBranch,m); sdd_deref(minBoxVarsSdd,m); //std::cout << *literalsToAtoms[minLits[0]] << " and " << *literalsToAtoms[minLits[1]] << "\n"; SddNode* beta = refineSdd(minLits, alpha, m); sdd_ref(beta,m); dependentSdds.insert(alpha); bool isSat = isSatisfiableRefined(beta, m, permVars, permSdd, assumedSatSdds, responsibleVars); dependentSdds.erase(alpha); sdd_deref(beta,m); sdd_deref(branchSdd,m); sdd_deref(newPermSdd,m); return isSat; } } } // There were new boxes, so recurse. if (!unboxed.empty()) { dependentSdds.insert(alpha); std::unordered_set<SddLiteral> postResponsibleVars; if (!isSatisfiable(postUnboxingBranch,m,newPermVars,newPermSdd,assumedSatSdds, postResponsibleVars)) { std::vector<SddLiteral> minLits; for (SddLiteral v : branch) { if (postResponsibleVars.count(v) == 1) { minLits.push_back(v); responsibleVars.insert(v); } } for (SddLiteral v : unboxed) { std::unordered_set<SddLiteral> children; KFormula::computeChildrenBoxS4(&literalsToAtoms[v]->getleft(), children); if (shareAnElement(postResponsibleVars, children)) { minLits.push_back(v); responsibleVars.insert(v); } } SddNode* beta = refineSdd(minLits, alpha, m); sdd_ref(beta,m); bool isSat = isSatisfiableRefined(beta, m, permVars, permSdd, assumedSatSdds, responsibleVars); sdd_deref(beta,m); sdd_deref(branchSdd,m); sdd_deref(newPermSdd,m); sdd_deref(postUnboxingBranch,m); dependentSdds.erase(alpha); return isSat; } sdd_deref(branchSdd,m); sdd_deref(newPermSdd,m); dependentSdds.erase(alpha); return true; } // There are no new boxes, so start undiamonding. sdd_deref(branchSdd,m); if (negBoxes.empty()) { return true; } dependentSdds.insert(alpha); SddNode* nextWorld; for (SddLiteral i : negBoxes) { nextWorld = sdd_conjoin(permSdd, sdd_negate(compiler::KtoSDD(&literalsToAtoms[-i]->getleft(),m),m),m); sdd_ref(nextWorld,m); if (sdd_node_is_false(nextWorld)) { sdd_deref(nextWorld,m); nextWorld = sdd_conjoin(sdd_manager_true(m), sdd_negate(compiler::KtoSDD(&literalsToAtoms[-i]->getleft(),m),m),m); sdd_ref(nextWorld,m); responsibleVars.insert(i); std::vector<SddLiteral> minLits; minLits.push_back(i); // Determine a minimal unsatisfiable subset. std::unordered_set<SddLiteral>::iterator endIt = permVars.end(); SddNode* minimalSdd = sdd_conjoin(nextWorld, sdd_manager_true(m),m); sdd_ref(minimalSdd,m); while (true) { sdd_deref(nextWorld,m); nextWorld = sdd_conjoin(minimalSdd, sdd_manager_true(m), m); sdd_ref(nextWorld,m); if (sdd_node_is_false(nextWorld)) break; for (std::unordered_set<SddLiteral>::iterator v = permVars.begin(); v != endIt; ++v) { nextWorld = sdd_conjoin(tmp = nextWorld,compiler::KtoSDD(&literalsToAtoms[*v]->getleft(),m) ,m); sdd_deref(tmp, m); sdd_ref(nextWorld,m); nextWorld = sdd_conjoin(tmp = nextWorld,sdd_manager_literal(*v,m) ,m); sdd_deref(tmp, m); sdd_ref(nextWorld,m); if (sdd_node_is_false(nextWorld)) { minimalSdd = sdd_conjoin(tmp = minimalSdd,compiler::KtoSDD(&literalsToAtoms[*v]->getleft(),m) ,m); sdd_deref(tmp, m); sdd_ref(minimalSdd,m); minimalSdd = sdd_conjoin(tmp = minimalSdd,sdd_manager_literal(*v,m) ,m); sdd_deref(tmp, m); sdd_ref(minimalSdd,m); minLits.push_back(*v); responsibleVars.insert(*v); endIt = v; break; } } } SddNode* beta = refineSdd(minLits, alpha, m); sdd_ref(beta,m); bool isSat = isSatisfiableRefined(beta, m, permVars, permSdd, assumedSatSdds, responsibleVars); sdd_deref(beta,m); sdd_deref(nextWorld,m); sdd_deref(minimalSdd,m); dependentSdds.erase(alpha); return isSat; } if (dependentSdds.count(nextWorld) == 1) { //Loop detected assumedSatSdds.insert(nextWorld); continue; } std::unordered_set<SddNode*,SddHasher> postModalAssumedSatSdds = assumedSatSdds; std::unordered_set<SddLiteral> postResponsibleVars; if (!isSatisfiable(nextWorld,m,permVars,permSdd,postModalAssumedSatSdds, postResponsibleVars)) { std::vector<SddLiteral> minLits; bool newPostModalJumpResVarsAdded = true; while (newPostModalJumpResVarsAdded) { newPostModalJumpResVarsAdded = false; for (std::unordered_set<SddLiteral>::iterator v = permVars.begin(); v != permVars.end(); ++v) { if (responsibleVars.count(*v) != 0) { continue; } std::unordered_set<SddLiteral> children = getChildren(*v); children.insert(*v); if (shareAnElement(postResponsibleVars, children)) { minLits.push_back(*v); responsibleVars.insert(*v); // Add in other children to postModalJumpResVars postResponsibleVars.insert(children.begin(), children.end()); newPostModalJumpResVarsAdded = true; } } if (responsibleVars.count(i) != 0) { // Don't bother, we've already accounted for this dia var. } else if (shareAnElement(postResponsibleVars, getChildren(i))) { // Note, <>phi stored as []~phi, thus the nith. minLits.push_back(i); responsibleVars.insert(i); // Add in other children to postModalJumpResVars postResponsibleVars.insert(getChildren(i).begin(), getChildren(i).end()); newPostModalJumpResVarsAdded = true; } } SddNode* beta = refineSdd(minLits, alpha, m); sdd_ref(beta,m); bool isSat = isSatisfiableRefined(beta, m, permVars, permSdd, assumedSatSdds, responsibleVars); sdd_deref(beta,m); sdd_deref(nextWorld,m); dependentSdds.erase(alpha); return isSat; } assumedSatSdds.insert(postModalAssumedSatSdds.begin(),postModalAssumedSatSdds.end()); } satCache.insert(alpha); dependentSdds.erase(alpha); return true; }
SddNode* cfgWithRef(SddManager* m, Vtree* v, int nonTerminal, int terminal, int rules[][3], int start, int ruleCount, int* string, int len){ SddNode* dy[len][len][nonTerminal]; int i,j,k,index; //initialize everything to false for (i=0;i<len;i++) for (j=0;j<len;j++) for (k=0;k<nonTerminal;k++) dy[i][j][k] = sdd_manager_false(m); sdd_manager_auto_gc_and_minimize_on(m); //set diagonal according to terminal rules for (index = 0;index < len; index++){ for (i = 0; i < ruleCount; i++){ if (rules[i][0] == -1 && rules[i][2] == string[index]){ dy[index][index][rules[i][1]] = sdd_manager_true(m); } } } //this section builds a dynamic array according to number of parsings //build from top down(according to diagram above) for (j = 1; j < len; j++){ //build from right to left for (i = j-1; i >= 0; i--){ //check each non-terminal rule for (k = 0; rules[k][0] != -1; k++){ for (index = 0; index+i < j; index++){ if (dy[i][i+index][rules[k][1]] && dy[i+index+1][j][rules[k][2]]){ SddNode* tmp = sdd_apply_in_vtree(dy[i][i+index][rules[k][1]],dy[i+index+1][j][rules[k][2]],0,v,m); sdd_ref(tmp,m); dy[i][j][rules[k][0]] = sdd_apply_in_vtree(dy[i][j][rules[k][0]],tmp,1,v,m); sdd_ref(dy[i][j][rules[k][0]],m); sdd_deref(tmp,m); } } } } } //this section builds a dynamic array according to number of parsings //build from top down(according to diagram above) for (j = 1; j < len; j++){ //build from right to left for (i = j-1; i >= 0; i--){ //check each non-terminal rule for (k = 0; rules[k][0] != -1; k++){ for (index = 0; index+i < j; index++){ if (dy[i][i+index][rules[k][1]] && dy[i+index+1][j][rules[k][2]]){ if (i != 0 || j != len-1 || rules[k][0] != start) sdd_deref(dy[i][j][rules[k][0]],m); } } } } } //int size = sdd_manager_size(m); int size = sdd_size(dy[0][len-1][start]); printf("size: %d\n",size); dy[0][len-1][start] = sdd_minimize_cardinality(dy[0][len-1][start],m); size = sdd_size(dy[0][len-1][start]); printf("size: %d\n",size); return dy[0][len-1][start]; }