def _build(bdd, expr, i): """ Recursive build function. Exponential algorithm. Easy to implement. Terrible performance """ #Base Case if i > bdd["n"]: pb.simplify(expr) return 1 if expr["value"] else 0 #The variable to consider var = bdd["var_order"][i-1] #propagate false expr1 = copy.deepcopy(expr) expr1 = pb.propagate(expr1, (var, False)) #propagate true expr = pb.propagate(expr, (var, True)) #get high and low edges low = _build(bdd, expr1, i+1) high = _build(bdd, expr, i+1) return _mk(bdd, i, low, high)
def bdd_init(fName): """ Initializes a BDD data structure (dictionary) with the Boolean Formula stored in file name FNAME """ #parse file using PyBool expr = pb.parse_std(fName) var_order = expr["var_order"] expr = expr["main_expr"] #make sure all variables are accounted for assert(len(var_order) >= pb.number_vars(expr)) #values are tuples in the form (i, low, high) t_table = {0 : ((len(var_order)+1), None, None), 1 : ((len(var_order)+1), None, None)} return {"u" : 1 , "n" : len(var_order), "h_table" : {} , "t_table" : t_table , #boolean formula info "var_order" : var_order , "expr" : expr }
def bdd_init(example): """ Initializes a BDD data structure (dictionary) with the Boolean Formula stored in file name FNAME """ #parse file using PyBool expr = pb.parse_std(example) var_order = expr["var_order"] expr = expr["main_expr"] #make sure all variables are accounted for assert (len(var_order) >= pb.number_vars(expr)) #values are tuples in the form (i, low, high) t_table = { 0: ((len(var_order) + 1), None, None), 1: ((len(var_order) + 1), None, None) } return { "u": 1, "n": len(var_order), "h_table": {}, "t_table": t_table, #boolean formula info "var_order": var_order, "expr": expr }
def _build(bdd, expr, i): """ Recursive build function. Exponential algorithm. Easy to implement. Terrible performance """ #Base Case if i > bdd["n"]: pb.simplify(expr) return 1 if expr["value"] else 0 #The variable to consider var = bdd["var_order"][i - 1] #propagate false expr1 = copy.deepcopy(expr) expr1 = pb.propagate(expr1, (var, False)) #propagate true expr = pb.propagate(expr, (var, True)) #get high and low edges low = _build(bdd, expr1, i + 1) high = _build(bdd, expr, i + 1) return _mk(bdd, i, low, high)
def ite_build(bdd): """ Public Function that initializes the main expression for the recursive ite function and takes care of the corner cases (all True and all False) """ expr = copy.deepcopy(bdd["expr"]) expr = pb.simplify(expr) F, G, H = _parse_ite(expr) x = _ite(bdd, F, G, H) #Corner Case if bdd["u"] == 1: bdd["u"] = x
def ite_build(bdd): """ Public Function that initializes the main expression for the recursive ite function and takes care of the corner cases (all True and all False) """ expr = copy.deepcopy(bdd["expr"]) expr = pb.simplify(expr) F,G,H = _parse_ite(expr) x = _ite(bdd, F, G, H) #Corner Case if bdd["u"] == 1: bdd["u"] = x
def top_variable(bdd, F, G, H): """ Given 3 expressions (F, G, H) and a bdd dictionary, returns the top variable in the three expressions. (Could possibly be faster by passing a minimum argument so that the whole var_order list doesn't have to be traversed) """ #Make a big list with all the variables in it. exp_vars = pb.get_vars(F) exp_vars.extend(pb.get_vars(G)) exp_vars.extend(pb.get_vars(H)) #Turn it into a set. exp_vars = set(exp_vars) #Traverse through all the variables in #var_order and return the one that appears #first. for x in bdd["var_order"]: if x in exp_vars: return x #else return None. return None
def top_variable(bdd, F,G,H): """ Given 3 expressions (F, G, H) and a bdd dictionary, returns the top variable in the three expressions. (Could possibly be faster by passing a minimum argument so that the whole var_order list doesn't have to be traversed) """ #Make a big list with all the variables in it. exp_vars = pb.get_vars(F) exp_vars.extend(pb.get_vars(G)) exp_vars.extend(pb.get_vars(H)) #Turn it into a set. exp_vars = set(exp_vars) #Traverse through all the variables in #var_order and return the one that appears #first. for x in bdd["var_order"]: if x in exp_vars: return x #else return None. return None
def buildBDDmain(example): try: bdd = BDD.bdd_init( example) # "python/programoutput/" + uniqid + ".txt" except pb.Parse_Error as e: ERR_str = "There was an error parsing your file, please check your syntax\n" \ + e.value + "\n" exit_err() if len(bdd["var_order"]) > BDD_VAR_LENGTH: ERR_str = "Your formula contains too many variables for the web interface. Please try again with less than 14 variables or download the BDD package and run it on your own machine." exit_err() if len(pb.print_expr(bdd["expr"])) > 500: ERR_str = "Your formula is too long for the web interface. Please try again with a smaller formula or download the BDD package and run it on your own machine." exit_err() BDD.ite_build(bdd) stats = BDD.stat_string(bdd) sat_count = BDD.sat_count(bdd) variable_order = bdd["var_order"] sat_assigns = BDD.all_sat(bdd) sat_assigns_string = "" for x in sat_assigns: sat_assigns_string += str(list(map(lambda y: 0 if '~' in y else 1, x))) + '\n' dot_file = uniqid + ".dot" # print("dot_file = ", dot_file) # print("BDD = ", bdd) BDD.dot_bdd(bdd, dot_file) #print reduce(lambda x, y : x + " " + y, [dot_PATH, dot_ARGS, dot_file, dot_OUT]) #err = os.system(reduce(lambda x, y : x + " " + y, [dot_PATH, dot_ARGS, dot_file, dot_OUT])) #print( rm + " " + dot_file ) # print("Dot file left behind as", dot_file) #os.system(rm + " " + dot_file) # if err != 0: # ERR_str = "There was an error running dot on the server" # exit_err() STAT_str = "Number of satisfying assignments: " + str(sat_count) + "\n"\ + stats + "\n\nAll satisfying assignments:\n" + "------------------------------\n"\ + sat_assigns_string print("Satisfying string is", STAT_str)
def PySat_dpll(clauses): # pdb.set_trace() if len(clauses) == 0: return True if True in [len(x) == 0 for x in clauses]: return False # pdb.set_trace() unit_C = Bool.cnf_get_unit_clauses(clauses) for unit in unit_C: clauses = Bool.cnf_propagate(clauses, Bool.cnf_get_var(unit), Bool.cnf_get_sign(unit)) # pdb.set_trace() pureLits = Bool.cnf_get_pure_literals(clauses) # pdb.set_trace() for pl in pureLits: clauses = Bool.cnf_propagate(clauses, Bool.cnf_get_var(pl), Bool.cnf_get_sign(pl)) # pdb.set_trace() if len(clauses) == 0: return True if True in [len(x) == 0 for x in clauses]: return False # pdb.set_trace() newVar = chooseVar(clauses) trueClause = Bool.cnf_propagate(copy.deepcopy(clauses), Bool.cnf_get_var(newVar),True) if PySat_dpll(trueClause): return True falseClause = Bool.cnf_propagate(copy.deepcopy(clauses), Bool.cnf_get_var(newVar),False) if PySat_dpll(falseClause): return True return False;
import copy import sys sys.path.append("../include/") import PyBool_public_interface as Bool import PyBool_builder as BoolB import pdb #Good example to demo PyBool. Step through with pdb, and print #variables at each stage. For the recursive representations (expr and expr2) #use Bool.print_expr(expr) for pretty printing. Uses very simple DIMACS #file example_dimacs_files/lecture.cnf if __name__ == "__main__": #Read and parse a dimacs file clauses = Bool.parse_dimacs("example_dimacs_files/lecture.cnf") clauses = clauses["clauses"] #convert dimacs form to recursive form expr = Bool.cnf_to_rec(clauses) #make a new formula that is the negation of previous expr = BoolB.mk_neg_expr(expr) expr2 = copy.deepcopy(expr) #Put in negation normal form expr = Bool.nne(expr) #now make a possibly exp. sized cnf expr = Bool.exp_cnf(expr)
#! /usr/bin/env python2.7 import sys sys.path.append("../../include/") import PyBool_public_interface as Bool if __name__ == "__main__": expr = Bool.parse_std("input.txt") expr = expr["main_expr"] expr = Bool.simplify(expr) expr = Bool.nne(expr) print Bool.print_expr(expr)
# pdb.set_trace() newVar = chooseVar(clauses) trueClause = Bool.cnf_propagate(copy.deepcopy(clauses), Bool.cnf_get_var(newVar),True) if PySat_dpll(trueClause): return True falseClause = Bool.cnf_propagate(copy.deepcopy(clauses), Bool.cnf_get_var(newVar),False) if PySat_dpll(falseClause): return True return False; #Choose the next variable to assign. Just choose a variable in the smallest clause def chooseVar(clauses): minC = clauses[0] for x in clauses: if len(x) < len(minC): minC = x return minC[0] if __name__ == "__main__": clauses = Bool.parse_dimacs("example_dimacs_files/75VarSat.cnf") print (PySat_dpll(clauses["clauses"]))
def _ite(bdd, F, G, H): """ Main recursive method. Follows Bryants paper with a few added heuristics which are noted. """ #################### #Possible Base Cases #################### #If G and H and constants: # #Base case if F is a variable or constant #Else Parse F into FGH form. if _is_const(G, True) and _is_const(H, False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0], 1, 0) elif F["type"] == "const": return 1 if F["value"] else 0 else: F, G, H = _parse_ite(F) elif _is_const(H, True) and _is_const(G, False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0], 0, 1) elif F["type"] == "const": return 0 if F["value"] else 1 else: F, G, H = _parse_ite(F) #################### #if H and G are equal and constant #Just return what H and G are (my heuristic) elif _is_const(G, False) and _is_const(H, False): return 0 elif _is_const(G, True) and _is_const(H, True): return 1 #################### #If F is a const, then we only have to consider #Either G or H. Base case if they're variable otherwise #parse them into F, G, H elif _is_const(F, True): if G["type"] == "var": return _ite_mk(bdd, G["name"][0], 1, 0) else: F, G, H = _parse_ite(G) elif _is_const(F, False): if H["type"] == "var": return _ite_mk(bdd, H["name"][0], 1, 0) else: F, G, H = _parse_ite(H) #################### #Find the top variable. v = top_variable(bdd, F, G, H) #create new expressions with variable propagated Fv, Gv, Hv = copy.deepcopy(F), copy.deepcopy(G), copy.deepcopy(H) Fv = pb.propagate(Fv, (v, True)) Gv = pb.propagate(Gv, (v, True)) Hv = pb.propagate(Hv, (v, True)) Fnv = pb.propagate(F, (v, False)) Gnv = pb.propagate(G, (v, False)) Hnv = pb.propagate(H, (v, False)) #Recursively find T (then) and E (else) nodes T = _ite(bdd, Fv, Gv, Hv) E = _ite(bdd, Fnv, Gnv, Hnv) #If they're the same, then we don't need to make a new #node if T == E: return T #make a new node and return it R = _ite_mk(bdd, v, T, E) return R
def _ite(bdd, F, G, H): """ Main recursive method. Follows Bryants paper with a few added heuristics which are noted. """ #################### #Possible Base Cases #################### #If G and H and constants: # #Base case if F is a variable or constant #Else Parse F into FGH form. #Switching the _ite_mk args, because they seem to be backwards! while (_is_const(G, True) and _is_const(H, False)) or (_is_const(H, True) and _is_const( G, False)) and (F["type"] == "neg" or F["type"] == "var"): if _is_const(G, True) and _is_const(H, False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0], 0, 1) elif F["type"] == "const": return 1 if F["value"] else 0 else: F, G, H = _parse_ite(F) elif _is_const(H, True) and _is_const(G, False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0], 1, 0) elif F["type"] == "const": return 0 if F["value"] else 1 else: #Fix applied Feb. 16, 2013 by Tyler Sorensen F, G, H = _parse_ite(F) H = pbb.mk_neg_expr(H) G = pbb.mk_neg_expr(G) #################### #if H and G are equal and constant #Just return what H and G are (my heuristic) if _is_const(G, False) and _is_const(H, False): return 0 elif _is_const(G, True) and _is_const(H, True): return 1 #################### #Bug fix : forgot to check for these cases elif _is_const(F, False) and _is_const(H, True): return 1 elif _is_const(F, False) and _is_const(H, False): return 0 elif _is_const(F, True) and _is_const(G, False): return 0 elif _is_const(F, True) and _is_const(G, True): return 1 #################### #If F is a const, then we only have to consider #Either G or H. Base case if they're variable otherwise #parse them into F, G, H elif _is_const(F, True): if G["type"] == "var": return _ite_mk(bdd, G["name"][0], 0, 1) else: F, G, H = _parse_ite(G) elif _is_const(F, False): if H["type"] == "var": return _ite_mk(bdd, H["name"][0], 0, 1) else: F, G, H = _parse_ite(H) #################### #Find the top variable. v = top_variable(bdd, F, G, H) #create new expressions with variable propagated Fv, Gv, Hv = copy.deepcopy(F), copy.deepcopy(G), copy.deepcopy(H) Fv = pb.propagate(Fv, (v, True)) Gv = pb.propagate(Gv, (v, True)) Hv = pb.propagate(Hv, (v, True)) Fnv = pb.propagate(F, (v, False)) Gnv = pb.propagate(G, (v, False)) Hnv = pb.propagate(H, (v, False)) #Recursively find T (then) and E (else) nodes T = _ite(bdd, Fv, Gv, Hv) E = _ite(bdd, Fnv, Gnv, Hnv) #If they're the same, then we don't need to make a new #node #pdb.set_trace() if T == E: return T #make a new node and return it R = _ite_mk(bdd, v, E, T) return R
#!/usr/bin/env python import sys import copy sys.path.append("/home/robbean/Uned/sw/PBL/PBL-master/include/") sys.setrecursionlimit(10000) import PyBool_public_interface as Bool if __name__ == "__main__": if len(sys.argv) > 1: clauses = Bool.parse_std(sys.argv[1]) #expr = Bool.exp_cnf(clauses["main_expr"]) nne = Bool.nne(clauses["main_expr"]) cnf = Bool.exp_cnf(nne)
if __name__ == "__main__": try: bdd = BDD.bdd_init("python/programoutput/" + uniqid + ".txt") except pb.Parse_Error as e: ERR_str = "There was an error parsing your file, please check your syntax\n" \ + e.value + "\n" exit_err() if len(bdd["var_order"]) > 14: ERR_str = "Your formula contains too many variables for the web interface. Please try again with less than 14 variables or download the BDD package and run it on your own machine." exit_err() if len(pb.print_expr(bdd["expr"])) > 500: ERR_str = "Your formula is too long for the web interface. Please try again with a smaller formula or download the BDD package and run it on your own machine." exit_err() BDD.reorder_ite_build(bdd) stats = BDD.stat_string(bdd) sat_count = BDD.sat_count(bdd) variable_order = bdd["var_order"] sat_assigns = BDD.all_sat(bdd) sat_assigns_string = "" for x in sat_assigns: sat_assigns_string += str(map(lambda y : 0 if '~' in y else 1, x)) + '\n' dot_file = "python/programoutput/" + uniqid + ".dot" BDD.dot_bdd(bdd, dot_file)
sys.path.append(PyBool_PATH) import PyBool_public_interface as pb ERR_str = "" STAT_str = "" def exit_err(): f = open("python/programoutput/error" + uniqid + ".txt", "w") f.write(ERR_str) f.close() exit(0) if __name__ == "__main__": try: expr = pb.parse_std("python/programoutput/" + uniqid + ".txt")["main_expr"] except pb.Parse_Error as e: ERR_str = "There was an error parsing your file, please check your syntax\n" \ + e.value + "\n" exit_err() if pb.number_vars(expr) > 14: ERR_str = "Your formula contains too many variables for the web interface. Please try again with less than 14 variables or download the PBL package and run it on your own machine." exit_err() if len(pb.print_expr(expr)) > 500: ERR_str = "Your formula is too long for the web interface. Please try again with a smaller formula or download the PBL package and run it on your own machine." exit_err()
if __name__ == "__main__": try: bdd = BDD.bdd_init("python/programoutput/" + uniqid + ".txt") except pb.Parse_Error as e: ERR_str = "There was an error parsing your file, please check your syntax\n" \ + e.value + "\n" exit_err() if len(bdd["var_order"]) > BDD_VAR_LENGTH: ERR_str = "Your formula contains too many variables for the web interface. Please try again with less than 14 variables or download the BDD package and run it on your own machine." exit_err() if len(pb.print_expr(bdd["expr"])) > 500: ERR_str = "Your formula is too long for the web interface. Please try again with a smaller formula or download the BDD package and run it on your own machine." exit_err() BDD.reorder_ite_build(bdd) stats = BDD.stat_string(bdd) sat_count = BDD.sat_count(bdd) variable_order = bdd["var_order"] sat_assigns = BDD.all_sat(bdd) sat_assigns_string = "" for x in sat_assigns: sat_assigns_string += str(map(lambda y: 0 if '~' in y else 1, x)) + '\n' dot_file = "python/programoutput/" + uniqid + ".dot"
ERR_str = "" STAT_str = "" def exit_err(): f = open("python/programoutput/error" + uniqid + ".txt", "w") f.write(ERR_str) f.close() exit(0) if __name__ == "__main__": try: expr = pb.parse_std("python/programoutput/" + uniqid + ".txt")["main_expr"] except pb.Parse_Error as e: ERR_str = "There was an error parsing your file, please check your syntax\n" \ + e.value + "\n" exit_err() if pb.number_vars(expr) > PBL_VAR_LENGTH: ERR_str = "Your formula contains too many variables for the web interface. Please try again with less than 14 variables or download the PBL package and run it on your own machine." exit_err() if len(pb.print_expr(expr)) > 500: ERR_str = "Your formula is too long for the web interface. Please try again with a smaller formula or download the PBL package and run it on your own machine." exit_err() expr = pb.exp_cnf(expr)
def _ite(bdd,F,G,H): """ Main recursive method. Follows Bryants paper with a few added heuristics which are noted. """ #################### #Possible Base Cases #################### #If G and H and constants: # #Base case if F is a variable or constant #Else Parse F into FGH form. #Switching the _ite_mk args, because they seem to be backwards! while (_is_const(G,True) and _is_const(H,False)) or (_is_const(H,True) and _is_const(G,False)) and (F["type"] == "neg" or F["type"] == "var"): if _is_const(G,True) and _is_const(H,False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0] ,0,1) elif F["type"] == "const": return 1 if F["value"] else 0 else: F,G,H = _parse_ite(F) elif _is_const(H,True) and _is_const(G,False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0] ,1,0) elif F["type"] == "const": return 0 if F["value"] else 1 else: #Fix applied Feb. 16, 2013 by Tyler Sorensen F,G,H = _parse_ite(F) H = pbb.mk_neg_expr(H) G = pbb.mk_neg_expr(G) #################### #if H and G are equal and constant #Just return what H and G are (my heuristic) if _is_const(G, False) and _is_const(H, False): return 0 elif _is_const(G,True) and _is_const(H,True): return 1 #################### #Bug fix : forgot to check for these cases elif _is_const(F,False) and _is_const(H,True): return 1 elif _is_const(F,False) and _is_const(H,False): return 0 elif _is_const(F,True) and _is_const(G,False): return 0 elif _is_const(F,True) and _is_const(G,True): return 1 #################### #If F is a const, then we only have to consider #Either G or H. Base case if they're variable otherwise #parse them into F, G, H elif _is_const(F,True): if G["type"] == "var": return _ite_mk(bdd,G["name"][0],0,1) else: F,G,H = _parse_ite(G) elif _is_const(F,False): if H["type"] == "var": return _ite_mk(bdd, H["name"][0],0,1) else: F,G,H = _parse_ite(H) #################### #Find the top variable. v = top_variable(bdd, F,G,H) #create new expressions with variable propagated Fv, Gv, Hv = copy.deepcopy(F), copy.deepcopy(G), copy.deepcopy(H) Fv = pb.propagate(Fv, (v, True)) Gv = pb.propagate(Gv, (v, True)) Hv = pb.propagate(Hv, (v, True)) Fnv = pb.propagate(F, (v, False)) Gnv = pb.propagate(G, (v, False)) Hnv = pb.propagate(H, (v, False)) #Recursively find T (then) and E (else) nodes T = _ite(bdd, Fv, Gv, Hv) E = _ite(bdd, Fnv, Gnv, Hnv) #If they're the same, then we don't need to make a new #node #pdb.set_trace() if T == E: return T #make a new node and return it R = _ite_mk(bdd,v,E,T) return R
#!/usr/bin/env python import sys import copy sys.path.append("/home/robbean/Uned/sw/PBL/PBL-master/include/") sys.setrecursionlimit(10000) import PyBool_public_interface as Bool if __name__ == "__main__": if len(sys.argv) > 1: clauses = Bool.parse_std(sys.argv[1]) expr = Bool.nne(clauses["main_expr"]) print Bool.print_expr(expr)
def _ite(bdd,F,G,H): """ Main recursive method. Follows Bryants paper with a few added heuristics which are noted. """ #################### #Possible Base Cases #################### #If G and H and constants: # #Base case if F is a variable or constant #Else Parse F into FGH form. if _is_const(G,True) and _is_const(H,False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0] ,1,0) elif F["type"] == "const": return 1 if F["value"] else 0 else: F,G,H = _parse_ite(F) elif _is_const(H,True) and _is_const(G,False): if F["type"] == "var": return _ite_mk(bdd, F["name"][0] ,0,1) elif F["type"] == "const": return 0 if F["value"] else 1 else: F,G,H = _parse_ite(F) #################### #if H and G are equal and constant #Just return what H and G are (my heuristic) elif _is_const(G, False) and _is_const(H, False): return 0 elif _is_const(G,True) and _is_const(H,True): return 1 #################### #If F is a const, then we only have to consider #Either G or H. Base case if they're variable otherwise #parse them into F, G, H elif _is_const(F,True): if G["type"] == "var": return _ite_mk(bdd,G["name"][0],1,0) else: F,G,H = _parse_ite(G) elif _is_const(F,False): if H["type"] == "var": return _ite_mk(bdd, H["name"][0],1,0) else: F,G,H = _parse_ite(H) #################### #Find the top variable. v = top_variable(bdd, F,G,H) #create new expressions with variable propagated Fv, Gv, Hv = copy.deepcopy(F), copy.deepcopy(G), copy.deepcopy(H) Fv = pb.propagate(Fv, (v, True)) Gv = pb.propagate(Gv, (v, True)) Hv = pb.propagate(Hv, (v, True)) Fnv = pb.propagate(F, (v, False)) Gnv = pb.propagate(G, (v, False)) Hnv = pb.propagate(H, (v, False)) #Recursively find T (then) and E (else) nodes T = _ite(bdd, Fv, Gv, Hv) E = _ite(bdd, Fnv, Gnv, Hnv) #If they're the same, then we don't need to make a new #node if T == E: return T #make a new node and return it R = _ite_mk(bdd,v,T,E) return R
person(b). person(c). 0.2::stress(X) :- person(X). 0.1::friends(X,Y) :- person(X), person(Y). 0.3::smokes(X) :- stress(X). 0.4::smokes(X) :- friends(X,Y), smokes(Y). query(smokes(a)). """) lf2 = LogicFormula.create_from(p2, avoid_name_clash=True, keep_order=True, label_all=True) # print(LogicFormula.to_prolog(lf2)) dag2 = LogicDAG.create_from(lf2, avoid_name_clash=True, keep_order=True, label_all=True) print(dag2) print(LogicFormula.to_prolog(dag2)) cnf2 = CNF.create_from(dag2) # for clause in cnf2._clauses: # print(clause) ddnnf2 = DDNNF.create_from(cnf2) print(ddnnf2.evaluate()) import PyBool_public_interface as Bool expr = Bool.parse_std("input.txt") expr = expr["main_expr"] expr = Bool.exp_cnf(expr) print(Bool.print_expr(Bool.simplify(expr)))