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* cfgStringSdd(SddManager* m, int nonTerminal, int terminal, int rules[][3], int start, int ruleCount, int* string, int len){ sdd_manager_auto_gc_and_minimize_off(m); 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); //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]]){ dy[i][j][rules[k][0]] = sdd_disjoin(dy[i][j][rules[k][0]],sdd_conjoin(dy[i][i+index][rules[k][1]],dy[i+index+1][j][rules[k][2]],m),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); sdd_manager_auto_gc_and_minimize_on(m); return dy[0][len-1][start]; } }
bool S4Prover::isSatisfiable(SddNode* alpha, SddManager* m) { std::unordered_set<SddNode*,SddHasher> assumedSatSdds; std::unordered_set<SddLiteral> responsibleVars; return isSatisfiable(alpha,m,std::unordered_set<SddLiteral>(),sdd_manager_true(m), assumedSatSdds, responsibleVars); }
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; }
int main(int argc, char** argv) { // set up vtree and manager SddLiteral var_count = 5; int auto_gc_and_minimize = 0; SddManager* m = sdd_manager_create(var_count,auto_gc_and_minimize); SddLiteral A = 1, B = 2, C = 3, faulty1 = 4, faulty2 = 5; SddNode* delta = sdd_manager_true(m); SddNode* alpha; ////////// CONSTRUCT KNOWLEDGE BASE ////////// // ~faulty1 => ( A <=> ~B ) alpha = sdd_equiv(sdd_manager_literal(A,m),sdd_manager_literal(-B,m),m); alpha = sdd_imply(sdd_manager_literal(-faulty1,m),alpha,m); delta = sdd_conjoin(delta,alpha,m); // faulty1 => ( ( A <=> B ) v ~B ) alpha = sdd_equiv(sdd_manager_literal(A,m),sdd_manager_literal(B,m),m); alpha = sdd_disjoin(alpha,sdd_manager_literal(-B,m),m); alpha = sdd_imply(sdd_manager_literal(faulty1,m),alpha,m); delta = sdd_conjoin(delta,alpha,m); // ~faulty2 => ( B <=> ~C ) alpha = sdd_equiv(sdd_manager_literal(B,m),sdd_manager_literal(-C,m),m); alpha = sdd_imply(sdd_manager_literal(-faulty2,m),alpha,m); delta = sdd_conjoin(delta,alpha,m); // faulty2 => ( ( B <=> C ) v ~C ) alpha = sdd_equiv(sdd_manager_literal(B,m),sdd_manager_literal(C,m),m); alpha = sdd_disjoin(alpha,sdd_manager_literal(-C,m),m); alpha = sdd_imply(sdd_manager_literal(faulty2,m),alpha,m); delta = sdd_conjoin(delta,alpha,m); ////////// PERFORM QUERY ////////// int* variables; SddLiteral health_vars = 2, health_vars_count, missing_health_vars; // make observations delta = sdd_condition(A,delta,m); delta = sdd_condition(-C,delta,m); // check if observations are normal SddNode* gamma; gamma = sdd_condition(-faulty1,delta,m); gamma = sdd_condition(-faulty2,gamma,m); int is_abnormal = gamma == sdd_manager_false(m); // sdd_node_is_false(gamma,m); printf("observations normal? : %s\n", is_abnormal ? "abnormal":"normal"); // project onto faults SddNode* diagnosis = sdd_exists(B,delta,m); // diagnosis no longer depends on variables A,B or C // count the number of diagnoses SddModelCount count = sdd_model_count(diagnosis,m); // adjust for missing faults variables = sdd_variables(diagnosis,m); health_vars_count = variables[faulty1] + variables[faulty2]; missing_health_vars = health_vars - health_vars_count; count <<= missing_health_vars; // multiply by 2^missing_health_vars free(variables); // find minimum cardinality diagnoses SddNode* min_diagnosis = sdd_minimize_cardinality(diagnosis,m); variables = sdd_variables(min_diagnosis,m); // adjust for missing faults if ( variables[faulty1] == 0 ) min_diagnosis = sdd_conjoin(min_diagnosis,sdd_manager_literal(-faulty1,m),m); if ( variables[faulty2] == 0 ) min_diagnosis = sdd_conjoin(min_diagnosis,sdd_manager_literal(-faulty2,m),m) ; free(variables); // count the number of minimum cardinality diagnoses, and minimum cardinality SddModelCount min_count = sdd_model_count(min_diagnosis,m); SddLiteral min_card = sdd_minimum_cardinality(min_diagnosis); printf("sdd model count : %"PRImcS"\n",count); printf("sdd model count (min) : %"PRImcS"\n",min_count); printf("sdd cardinality : %"PRIlitS"\n",min_card); ////////// SAVE SDDS ////////// printf("saving sdd and dot ...\n"); sdd_save("output/circuit-kb.sdd",delta); sdd_save("output/diagnosis.sdd",diagnosis); sdd_save("output/diagnosis-min.sdd",min_diagnosis); sdd_save_as_dot("output/circuit-kb.dot",delta); sdd_save_as_dot("output/diagnosis.dot",diagnosis); sdd_save_as_dot("output/diagnosis-min.dot",min_diagnosis); ////////// CLEAN UP ////////// sdd_manager_free(m); return 0; }