コード例 #1
0
ファイル: prover.cpp プロジェクト: tpagram/sddtab
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;
}
コード例 #2
0
ファイル: s4Prover.cpp プロジェクト: tpagram/sddtab
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;
}
コード例 #3
0
ファイル: ckySdd.c プロジェクト: nhadfieldmenell/cfgSDD
/*
	# of literals = term*len + nonTerm*len*(len+1)/2
	first term*len literals:
		Terminal i corresponds to S(i/term,i%term)
	next nonTerm*len*(len+1)/2 correspond to non-terminals
	
	literal for T[i][j][k] = (j*(j+1)/2)*nonTerm+i*nonTerm+k + firstNon

*/
SddNode* sddParsings(SddManager*m, int nonTerm, int term, int nonRules[][3], int termRules[][2], int nonRuleCount, int termRuleCount, int start, int len){
	SddNode* S[term][len];
	int i,j,k,index;
	
	for(j = 0; j < len; j++){
		for(i = 0; i < term; i++){
			S[i][j] = sdd_manager_literal(j*term+i+1,m);
			for(k = 0; k < term; k++){
				if (k != i){
					S[i][j] = sdd_conjoin(sdd_manager_literal(0-(j*term+k+1),m),S[i][j],m);
				}
			}
		}
	}
	
	int firstNon = term*len+1;
	SddNode* T[len][len][nonTerm];
	
	//set diagonal according to terminal rules
	for (index = 0;index < len; index++){
		for(k = 0; k < nonTerm; k++){
			T[index][index][k] = sdd_manager_false(m);
		}	
		for(i = 0; i < termRuleCount; i++){
			k = termRules[i][0];
			int termVal = termRules[i][1];
			T[index][index][k] = sdd_disjoin(T[index][index][k],S[termVal][index],m);
		}
		for(k = 0; k < nonTerm; k++){
			T[index][index][k] = sdd_conjoin(T[index][index][k],sdd_manager_literal((index*(index+1)/2)*nonTerm+index*nonTerm+k + firstNon,m),m);
			for(j = 0; j < nonTerm; j++){
				if (j != k){
					T[index][index][k] = sdd_conjoin(T[index][index][k],sdd_manager_literal(0-((index*(index+1)/2)*nonTerm+index*nonTerm+j + firstNon),m),m);
				}
			}
		}
	}
	
	return T[0][0][0];
	
}
コード例 #4
0
//converts a clause/term into an equivalent sdd
//all variables of litset must appear in vtree
SddNode* apply_litset_manual(LitSet* litset, Vtree* vtree, SddManager* manager) {
  BoolOp op            = litset->op; //conjoin (term) or disjoin (clause)
  SddLiteral* literals = litset->literals;
  SddNode* node        = ONE(manager,op);
  
  for(SddLiteral i=0; i<litset->literal_count; i++) {
    SddNode* literal = sdd_manager_literal(literals[i],manager);
    node             = sdd_apply_in_vtree(node,literal,op,vtree,manager);
  }
  
  return node;
}
コード例 #5
0
ファイル: compiler-auto.c プロジェクト: hugopaquet/mcmas-sdds
//converts a clause/term into an equivalent sdd
SddNode* apply_litset_auto(LitSet* litset, SddManager* manager) {

  BoolOp op            = litset->op; //conjoin (term) or disjoin (clause)
  SddLiteral* literals = litset->literals;
  SddNode* node        = ONE(manager,op); //will not be gc'd
  
  for(SddLiteral i=0; i<litset->literal_count; i++) {
    SddNode* literal = sdd_manager_literal(literals[i],manager);
    node             = sdd_apply(node,literal,op,manager);
  }
  
  return node;
}
コード例 #6
0
ファイル: s4Prover.cpp プロジェクト: tpagram/sddtab
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;
}
コード例 #7
0
ファイル: circuit.c プロジェクト: hugopaquet/mcmas-sdds
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;
}
コード例 #8
0
ファイル: test-2.c プロジェクト: hugopaquet/mcmas-sdds
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;
}