def test_it4(): vtree = Vtree(var_count=4, var_order=[4, 3, 2, 1], vtree_type="right") sdd = SddManager.from_vtree(vtree) a, b, c, d = sdd.vars f1 = a | b f2 = f1 | c f3 = f2 | d f1.ref() f2.ref() f3.ref() if directory: litnamemap = {1: 'a', 2: 'b', 3: 'c', 4: 'd'} for key, val in list(litnamemap.items()): litnamemap[-key] = f"¬{val}" with (directory / "sdd.gv").open("w") as out: print(sdd_to_dot(f3, litnamemap=litnamemap, show_id=True), file=out) with (directory / "vtree.gv").open("w") as out: print(vtree_to_dot(sdd.vtree(), litnamemap=litnamemap, show_id=True), file=out) it = SddIterator(sdd, smooth=True) mc = it.depth_first(f1, SddIterator.func_modelcounting) assert mc == 3, "MC {} != 3".format(mc) it = SddIterator(sdd, smooth=True, smooth_to_root=True) mc = it.depth_first(f1, SddIterator.func_modelcounting) assert mc == 12, "MC {} != 3 * 2**2 = 12".format(mc)
def test_wmc2(verbose=False): vtree = Vtree(var_count=4, var_order=[2, 1, 4, 3], vtree_type="balanced") sdd = SddManager.from_vtree(vtree) a, b, c, d = [sdd.literal(i) for i in range(1, 5)] # formula = (a & b) | c formula = (a & b) | (b & c) | (c & d) # -d -c -b -a a b c d weights = array('d', [0.8, 0.7, 0.6, 0.5, 0.5, 0.4, 0.3, 0.2]) # Normal WMC wmc = WmcManager(formula, log_mode=False) wmc.set_literal_weights_from_array(weights) wmc_result = wmc.propagate() # Stochastic WMC wmcs = WmcStochastic(formula, log_mode=False) wmcs.set_literal_weights_from_array(weights) nb_pos, nb_neg, scaling = 0, 0, 1 wmcs_results = [] iterations = 1000 for i in range(iterations): random.seed() nb_pos_i, nb_neg_i, scaling_i = wmcs.propagate_counts(bitlength=10) nb_pos += nb_pos_i nb_neg += nb_neg_i scaling = scaling_i wmcs_results.append((nb_pos / (nb_pos + nb_neg)) * scaling) print(wmcs_results[-1]) if verbose: import matplotlib.pyplot as plt plt.plot([i * 10 for i in range(iterations)], [wmc_result] * iterations) plt.plot([i * 10 for i in range(iterations)], wmcs_results) plt.savefig("stochastic_wmc.png")
def test_it3(): """ Test case where formula = literal or -literal """ vtree = Vtree(var_count=4, var_order=[1, 2, 3, 4], vtree_type="right") sdd = SddManager.from_vtree(vtree) a, b, c, d = sdd.vars[:5] f = a wmc = f.wmc(log_mode=False) mc = wmc.propagate() # print(f"mc = {mc}") assert mc == 8.0 it = SddIterator(sdd, smooth=True, smooth_to_root=True) mc = it.depth_first(f, SddIterator.func_modelcounting) assert mc == 8, "MC {} != 8".format(mc) it = SddIterator(sdd, smooth=False, smooth_to_root=True) mc = it.depth_first(f, SddIterator.func_modelcounting) assert mc == 1, "MC (non-smooth) {} != 1".format(mc) f = -a wmc = f.wmc(log_mode=False) mc = wmc.propagate() # print(f"mc = {mc}") assert mc == 8.0 it = SddIterator(sdd, smooth=True, smooth_to_root=True) mc = it.depth_first(f, SddIterator.func_modelcounting) assert mc == 8, "MC {} != 8".format(mc) it = SddIterator(sdd, smooth=False, smooth_to_root=True) mc = it.depth_first(f, SddIterator.func_modelcounting) assert mc == 1, "MC (non-smooth) {} != 1".format(mc)
def main(): # set up vtree and manager vtree = Vtree.from_file("input/opt-swap.vtree".encode()) manager = SddManager.from_vtree(vtree) print("reading sdd from file ...") alpha = manager.read_sdd_file("input/opt-swap.sdd".encode()) print(f" sdd size = {alpha.size()}") # ref, perform the minimization, and then de-ref alpha.ref() print("minimizing sdd size ... ", end="") manager.minimize() # see also manager.minimize_limited() print("done!") print(f" sdd size = {alpha.size()}") alpha.deref() # augment the SDD print("augmenting sdd ...") beta = alpha * (manager.l(4) + manager.l(5)) print(f" sdd size = {beta.size()}") # ref, perform the minimization again on new SDD, and then de-ref beta.ref() print("minimizing sdd ... ", end="") manager.minimize() print("done!") print(f" sdd size = {beta.size()}") beta.deref()
def test_wmc1(verbose=False): vtree = Vtree(var_count=4, var_order=[2, 1, 4, 3], vtree_type="balanced") sdd = SddManager.from_vtree(vtree) a, b, c, d = [sdd.literal(i) for i in range(1, 5)] # formula = (a & b) | c formula = (a & b) | (b & c) | (c & d) if verbose: with open("sdd.dot", "w") as out: print(formula.dot(), file=out) # -d -c -b -a a b c d weights = array('d', [0.8, 0.7, 0.6, 0.5, 0.5, 0.4, 0.3, 0.2]) # Normal WMC wmc = WmcManager(formula, log_mode=False) print(f"MC = {wmc.propagate()}") wmc.set_literal_weights_from_array(weights) wmc_result = wmc.propagate() print(f"WMC-Normal = {wmc_result}") # Stochastic WMC wmcs = WmcStochastic(formula, log_mode=False) wmcs.set_literal_weights_from_array(weights) wmcs_result = wmcs.propagate(bitlength=1000) print(f"WMC-Stochastic = {wmcs_result}")
def main(): # Start from a given CNF and VTREE file vtree = Vtree.from_file(bytes(here / "input" / "simple.vtree")) sdd = SddManager.from_vtree(vtree) print(f"Created an SDD with {sdd.var_count()} variables") root = sdd.read_cnf_file(bytes(here / "input" / "simple.cnf")) # For DNF functions use `read_dnf_file` # If the vtree is not given, you can also use 'from_cnf_file` # Model Counting wmc = root.wmc(log_mode=True) w = wmc.propagate() print(f"Model count: {int(math.exp(w))}") # Weighted Model Counting lits = [None] + [sdd.literal(i) for i in range(1, sdd.var_count() + 1)] # Positive literal weight wmc.set_literal_weight(lits[1], math.log(0.5)) # Negative literal weight wmc.set_literal_weight(-lits[1], math.log(0.5)) w = wmc.propagate() print(f"Weighted model count: {math.exp(w)}") # Visualize SDD and VTREE print("saving sdd and vtree ... ", end="") with open(here / "output" / "sdd.dot", "w") as out: print(sdd.dot(), file=out) with open(here / "output" / "vtree.dot", "w") as out: print(vtree.dot(), file=out) print("done")
def test_it1(): vtree = Vtree(var_count=4, var_order=[1, 2, 3, 4], vtree_type="right") sdd = SddManager.from_vtree(vtree) a, b, c, d = sdd.vars[:5] f = ((a & b) | (c & d)) if directory: litnamemap = {1: 'a', 2: 'b', 3: 'c', 4: 'd'} for key, val in list(litnamemap.items()): litnamemap[-key] = f"¬{val}" with (directory / "sdd1.gv").open("w") as out: print(f.dot(), file=out) with (directory / "sdd2.gv").open("w") as out: print(sdd_to_dot(f, litnamemap=litnamemap, show_id=True), file=out) with (directory / "vtree1.gv").open("w") as out: print(sdd.vtree().dot(), file=out) with (directory / "vtree2.gv").open("w") as out: print(vtree_to_dot(sdd.vtree(), sdd, litnamemap=litnamemap, show_id=True), file=out) wmc = f.wmc(log_mode=False) mc = wmc.propagate() # print(f"mc = {mc}") assert mc == 7.0 it = SddIterator(sdd, smooth=True, smooth_to_root=True) mc = it.depth_first(f, SddIterator.func_modelcounting) assert mc == 7, "MC {} != 7".format(mc) it = SddIterator(sdd, smooth=False, smooth_to_root=True) mc = it.depth_first(f, SddIterator.func_modelcounting) assert mc == 3, "MC (non-smooth) {} != 3".format(mc)
def test_dnf1(): dnf_filename = str(here / "rsrc" / "test.cnf.nnf") fnf = Fnf.from_dnf_file(bytes(dnf_filename, encoding='utf8')) # weights = read_weights(dnf_filename) vtree = Vtree(var_count=fnf.var_count) manager = SddManager.from_vtree(vtree) node = manager.fnf_to_sdd(fnf) print(node)
def main(): # set up vtree and manager vtree = Vtree.from_file(bytes(here / "input" / "big-swap.vtree")) manager = SddManager.from_vtree(vtree) print("reading sdd from file ...") alpha = manager.read_sdd_file("input/big-swap.sdd".encode()) print(f" sdd size = {alpha.size()}") # to perform a swap, we need the manager's vtree manager_vtree = manager.vtree() # ref alpha (no dead nodes when swapping) alpha.ref() # using size of sdd normalized for manager_vtree as baseline for limit manager.init_vtree_size_limit(manager_vtree) limit = 2.0 manager.set_vtree_operation_size_limit(limit) print(f"modifying vtree (swap node 7) (limit growth by {limit:.1f}x) ... ", end="") succeeded = manager_vtree.swap(manager, 1) # limited print("succeeded!" if succeeded == 1 else "did not succeed!") print(f" sdd size = {alpha.size()}") print("modifying vtree (swap node 7) (no limit) ... ", end="") succeeded = manager_vtree.swap(manager, 0) # not limited print("succeeded!" if succeeded == 1 else "did not succeed!") print(f" sdd size = {alpha.size()}") print("updating baseline of size limit ...") manager.update_vtree_size_limit() left_vtree = manager_vtree.left() limit = 1.2 manager.set_vtree_operation_size_limit(limit) print(f"modifying vtree (swap node 5) (limit growth by {limit}x) ... ", end="") succeeded = left_vtree.swap(manager, 1) # limited print("succeeded!" if succeeded == 1 else "did not succeed!") print(f" sdd size = {alpha.size()}") limit = 1.3 manager.set_vtree_operation_size_limit(limit) print(f"modifying vtree (swap node 5) (limit growth by {limit}x) ... ", end="") succeeded = left_vtree.swap(manager, 1) # limited print("succeeded!" if succeeded == 1 else "did not succeed!") print(f" sdd size = {alpha.size()}") # deref alpha, since ref's are no longer needed alpha.deref()
def sddConstructorFromFile(self,sddFName): self.sddfName = sddFName if os.path.isfile(self.sddfName+".sdd") and os.path.isfile(self.sddfName+".vtree") and os.path.isfile(self.sddfName+".map") : with open(self.sddfName + ".map", "r") as f: self.nameMappingDic = json.load(f) vtree = Vtree.from_file((self.sddfName+".vtree").encode()) self.sdd = SddManager.from_vtree(vtree) self.formula = self.sdd.read_sdd_file((self.sddfName+".sdd").encode()) else: print("Please provide correct files") sys.exit()
def obdd_to_sdd(self,root,offset=0): from pysdd.sdd import Vtree, SddManager var_count = self.var_count + offset vtree = Vtree(var_count=var_count,vtree_type="right") mgr = SddManager.from_vtree(vtree) for node in root.__iter__(clear_data=True): if node.is_terminal(): alpha = mgr.true() if node.is_true() else mgr.false() else: dvar = node.dvar + offset plit,nlit = mgr.literal(dvar),mgr.literal(-dvar) alpha = (plit & node.hi.data) | (nlit & node.lo.data) node.data = alpha return (mgr,alpha)
def main(): # set up vtree and manager vtree = Vtree.from_file(bytes(here / "input" / "rotate-left.vtree")) manager = SddManager.from_vtree(vtree) # construct the term X_1 ^ X_2 ^ X_3 ^ X_4 x = [None] + [manager.literal(i) for i in range(1, 5)] alpha = x[1]*x[2]*x[3]*x[4] # to perform a rotate, we need the manager's vtree manager_vtree = manager.vtree() manager_vtree_right = manager_vtree.right() print("saving vtree & sdd ...") if not Path("output").is_dir(): raise Exception(f"Directory 'output' does not exist") manager_vtree.save_as_dot("output/before-rotate-vtree.dot".encode()) alpha.save_as_dot("output/before-rotate-sdd.dot".encode()) # ref alpha (so it is not gc'd) alpha.ref() # garbage collect (no dead nodes when performing vtree operations) print(f"dead sdd nodes = {manager.dead_count()}") print("garbage collection ...") manager.garbage_collect() print(f"dead sdd nodes = {manager.dead_count()}") print("left rotating ... ", end="") succeeded = manager_vtree_right.rotate_left(manager, 0) print("succeeded!" if succeeded == 1 else "did not succeed!") # deref alpha, since ref's are no longer needed alpha.deref() # the root changed after rotation, so get the manager's vtree again # this time using root_location manager_vtree = manager.vtree() print("saving vtree & sdd ...") if not Path("output").is_dir(): raise Exception(f"Directory 'output' does not exist") manager_vtree.save_as_dot("output/after-rotate-vtree.dot".encode()) alpha.save_as_dot("output/after-rotate-sdd.dot".encode())
def test_min1(): vtree = Vtree(var_count=4, var_order=[1, 4, 2, 3], vtree_type="right") sdd = SddManager.from_vtree(vtree) sdd.auto_gc_and_minimize_off() a, b, c, d = sdd.vars f = ((a & b) | (c & d)) f.ref() if directory: names = { 1: 'a', -1: '-a', 2: 'b', -2: '-b', 3: 'c', -3: '-c', 4: 'd', -4: '-d' } with (directory / "vtree1_before_a.gv").open("w") as out: print(sdd.vtree().dot(), file=out) with (directory / "vtree1_before_b.gv").open("w") as out: print(vtree_to_dot(sdd.vtree(), sdd, litnamemap=names, show_id=True), file=out) with (directory / "sdd1_before_a.gv").open("w") as out: print(sdd.dot(), file=out) with (directory / "sdd1_before_b.gv").open("w") as out: print(sdd_to_dot(sdd), file=out) sdd.minimize() if directory: with (directory / "vtree2_after.gv").open("w") as out: print(sdd.vtree().dot(), file=out) with (directory / "sdd1_after.gv").open("w") as out: print(sdd.dot(), file=out) f.deref() wmc = f.wmc(log_mode=False) mc = wmc.propagate() # print(f"mc = {mc}") assert mc == 7.0
def compile_to_sdd(formula: FNode, literals: LiteralInfo, vtree: Optional[Vtree]) -> SddNode: """ Compile a formula into an SDD. :param formula: The formula to represent as sdd. This formula must be a purely (abstracted) boolean formula (cf. extract_and_replace_literals(...) in literals.py) :param literals: The information of the literals in the formula :param vtree: The vtree to use. If None, a default vtree heuristic is used. :return: An SDD representing the given formula """ if SddManager is None: raise InstallError( "The pysdd package is required for this function but is not currently installed." ) if vtree is None: vtree = bami(literals) varnums = literals.numbered pysdd_vtree = vtree.to_pysdd(varnums) manager = SddManager.from_vtree(pysdd_vtree) converter = SddConversionWalker(manager, varnums) return converter.walk_smt(formula)
def main(): # set up vtree and manager var_count = 4 var_order = [2,1,4,3] vtree_type = "balanced" vtree = Vtree(var_count, var_order, vtree_type) manager = SddManager.from_vtree(vtree) # construct a formula (A^B)v(B^C)v(C^D) print("constructing SDD ... ") a, b, c, d = [manager.literal(i) for i in range(1, 5)] alpha = (a & b) | (b & c) | (c & d) print("done") print("saving sdd and vtree ... ") with open("output/sdd.dot", "w") as out: print(alpha.dot(), file=out) with open("output/vtree.dot", "w") as out: print(vtree.dot(), file=out) print("done")
def do_model_count(self, filename): # create vtree vtree_path = CounterFactory.create("minic2d").create_vtree(filename) vtree = Vtree.from_file(bytes(vtree_path.encode())) sdd = SddManager.from_vtree(vtree) # read CNF root = sdd.read_cnf_file(bytes(filename.encode())) # do model counting wmc = root.wmc(log_mode=False) # add weights weights = get_weights_from_cnf_file(filename) lits = [sdd.literal(i) for i in range(1, sdd.var_count() + 1)] assert len(weights) == 2 * len(lits), \ "Unexpected len {} for weights, got {}. Weights:\n{}".format(len(weights), 2 * len(lits), weights) for i in range(len(lits)): wmc.set_literal_weight(lits[i], weights[2 * i]) wmc.set_literal_weight(-lits[i], weights[2 * i + 1]) # write visualisation of SDD and Vtree to files sdd_file = os.path.abspath( os.path.join(os.path.dirname(filename), "sdd.")) vtree_file = os.path.abspath( os.path.join(os.path.dirname(filename), "vtree-sdd.")) with open(sdd_file + "dot", "w") as out: out.write(sdd.dot()) with open(vtree_file + "dot", "w") as out: out.write(vtree.dot()) # (graph,) = pydot.graph_from_dot_file(sdd_file + "dot") # graph.write_png(sdd_file + "png") # (graph,) = pydot.graph_from_dot_file(vtree_file + "dot") # graph.write_png(vtree_file + "png") return wmc.propagate()
def set_cnf(self, cnf, n_inputs, n_targets): self.n_inputs, self.n_targets = n_inputs, n_targets BASENAME = 'distillation-loss' # TODO avoid dumping stuff on disk with open(BASENAME + '.sympy', 'wt') as fp: fp.write(f'shape [{2 * n_inputs + n_targets}, {2}]\n') for clause in cnf.args: fp.write(f'{str(clause)}\n') ConstraintsToCnf.expression_to_cnf(BASENAME + '.sympy', BASENAME + '.dimacs', 1) fnf = Fnf.from_cnf_file(bytes(Path(BASENAME + '.dimacs'))) vtree = Vtree(var_count=fnf.var_count, vtree_type='balanced') manager = SddManager.from_vtree(vtree) sdd = manager.fnf_to_sdd(fnf) sdd.save(bytes(Path(BASENAME + '.sdd'))) manager.vtree().save(bytes(Path(BASENAME + '.vtree'))) self.sl = SemanticLoss(BASENAME + '.sdd', BASENAME + '.vtree')
def __init__(self, abducibles: List, mutuallyExclusive): self.abduciblesToSddLiterals = dict() self.SddLiteralsToOutputNeurons = dict() self.outputneuronsToAbducibles = dict() self.mutuallyExclusiveDict = dict() vtree = Vtree(var_count=len(abducibles), var_order=list(range(1, len(abducibles) + 1)), vtree_type="balanced") self.sddmanager = SddManager.from_vtree(vtree) index = 0 for abducible in abducibles: literal = self.sddmanager.literal(index + 1) self.abduciblesToSddLiterals[abducible] = literal self.SddLiteralsToOutputNeurons[literal] = index self.outputneuronsToAbducibles[index] = abducible index += 1 for i in range(len(mutuallyExclusive)): me = mutuallyExclusive[i] for abducible in me: fresh = me.copy() fresh.remove(abducible) self.mutuallyExclusiveDict[abducible] = fresh
def main(): arg_parser = argparse.ArgumentParser(description="problog pipeline") arg_parser.add_argument("--bif-file", "-b", help="The input bayesian network") arg_parser.add_argument("--pl-file", "-p", help="The input problog file") arg_parser.add_argument("cnf_file", help="The output cnf file") arg_parser.add_argument("--enc", "-e", default=1, help="The enc type 1 or 2", type=int) arg_parser.add_argument( "--cnf-type", "-c", default="c2d", help="The type of cnf file to output (c2d for minic2d or cachet)") arg_parser.add_argument("--verbose", "-v", default=False, help="Verbose output", type=bool, nargs='?', const=True) args = arg_parser.parse_args() if (args.bif_file is None and args.pl_file is None) or \ (args.bif_file is not None and args.pl_file is not None): print("one input file required") return -1 c2d = True if args.cnf_type == "c2d": c2d = True elif args.cnf_type == "cachet": c2d = False else: print("unknwon cnf type") return -1 is_bif = args.bif_file is not None file_name = args.bif_file if is_bif else args.pl_file enc1 = args.enc == 1 verbose = args.verbose contents = None with open(file_name, 'r') as f: contents = f.read() variables = None cnf = None weights = None evidence = None queries = None start_time = time.time() if is_bif: variables, cnf, weights, queries = parse_bif(contents, enc1, verbose) else: variables, cnf, weights, evidence, queries = parse_srl( contents, verbose) cnf_time = time.time() # if verbose: # print("cnf latex:") # print(len(cnf.args)) # clauses = cnf.args # for clause in clauses: # print("$", latex_print(clause), "$") # print() ints = cnf_to_ints(cnf, variables) if evidence is not None: for ev_name, ev_val in evidence: idx = variables.index(ev_name) + 1 if not ev_val: idx = -idx ints.append([idx]) save_cnf(args.cnf_file, ints, variables, weights, c2d) vtree_time = None if c2d: vtree_name = args.cnf_file + ".vtree" print("miniC2D:") minic2d = subprocess.run( [MINIC2D_PATH, '-c', args.cnf_file, '-o', vtree_name]) if minic2d.returncode != 0: print("error creating vtree") return -1 vtree_time = time.time() print("calculating sdd") vtree = Vtree.from_file(vtree_name.encode()) sdd = SddManager.from_vtree(vtree) root = sdd.read_cnf_file(args.cnf_file.encode()) print("sdd node count:", sdd.count()) print("sdd size:", sdd.size()) if verbose: sdd.print_stdout() print() wmc = root.wmc(log_mode=False) w = wmc.propagate() print("model count:", w) nlits = sdd.var_count() assert nlits == len(variables) for idx in range(nlits): i = idx + 1 w_pos = weights[variables[idx]][0] w_neg = weights[variables[idx]][1] wmc.set_literal_weight(sdd.literal(i), w_pos) wmc.set_literal_weight(sdd.literal(-i), w_neg) w = wmc.propagate() print("weighted count:", w) print() print("queries:") if queries is not None: for query in queries: idx = variables.index(query) + 1 pr = wmc.literal_pr(sdd.literal(idx)) print("P(", query, ") =\t", pr) end_time = time.time() print() print("cnf variables:", len(variables), "clauses: ", len(ints)) print() print("total time:\t", end_time - start_time) print("cnf time:\t", cnf_time - start_time) if vtree_time is not None: print("vtree time:\t", vtree_time - cnf_time) print("count time:\t", end_time - vtree_time) return 0
from pysdd.sdd import SddManager, Vtree var_count = 3 var_order = [1, 2, 3] vtree_type = 'balanced' vtree = Vtree(var_count, var_order, vtree_type) manager = SddManager.from_vtree(vtree) a, b, c = [manager.literal(i) for i in range(1, 4)] alpha = c & (a | -b) with open('sdd.dot', 'w') as out: print(alpha.dot(), file=out) with open('vtree.dot', 'w') as out: print(vtree.dot(), file=out)