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; }
// returns an SDD node representing ( node1 => node2 ) SddNode* sdd_imply(SddNode* node1, SddNode* node2, SddManager* manager) { return sdd_disjoin(sdd_negate(node1,manager),node2,manager); }