print("Boolector id " + b.GitId()) print() print(b.Copyright()) # Try pushing a context without enabling incremental usage, # raises Exception try: print("Expect exception to be raised (incremental usage not enabled).") b.Push() except BoolectorException as e: print("Caught exception: " + str(e)) # Try popping a context without first having pushed a context, # raises Exception try: b.Set_opt(pyboolector.BTOR_OPT_INCREMENTAL, True) print("Expect exception to be raised (no context pushed).") b.Pop() except BoolectorException as e: print("Caught exception: " + str(e)) ### Creating Boolector nodes # Sorts _boolsort = b.BoolSort() # Try creating a bit-vector sort of size 0, # raises Exception try: print("Expect exception to be raised (bit-vector size of 0).") _bvsort = b.BitVecSort(0) except BoolectorException as e:
def randomize(self, ri: RandInfo, bound_m: Dict[FieldModel, VariableBoundModel]): """Randomize the variables and constraints in a RandInfo collection""" # for rs in ri.randsets(): # print("RandSet") # for f in rs.all_fields(): # print(" " + f.name + " " + str(bound_m[f].domain.range_l)) # for uf in ri.unconstrained(): # print("Unconstrained: " + uf.name) rs_i = 0 start_rs_i = 0 max_fields = 20 while rs_i < len(ri.randsets()): btor = Boolector() self.btor = btor btor.Set_opt(pyboolector.BTOR_OPT_INCREMENTAL, True) btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, True) start_rs_i = rs_i constraint_l = [] # Collect up to max_fields fields to randomize at a time n_fields = 0 while rs_i < len(ri.randsets()): rs = ri.randsets()[rs_i] try: for f in rs.all_fields(): f.build(btor) n_fields += 1 except Exception as e: for c in rs.constraints(): print("Constraint: " + self.pretty_printer.do_print(c)) raise e constraint_l.extend( list( map( lambda c: (c, c.build(btor), isinstance(c, ConstraintSoftModel)), rs.constraints()))) rs_i += 1 if n_fields > max_fields: break for c in constraint_l: try: btor.Assume(c[1]) except Exception as e: from ..visitors.model_pretty_printer import ModelPrettyPrinter print("Exception: " + ModelPrettyPrinter.print(c[0])) raise e soft_node_l = list( map(lambda c: c[1], filter(lambda c: c[2], constraint_l))) node_l = list( map(lambda c: c[1], filter(lambda c: not c[2], constraint_l))) # Perform an initial solve to establish correctness if btor.Sat() != btor.SAT: if len(soft_node_l) > 0: # Try one more time before giving up for i, f in enumerate(btor.Failed(*soft_node_l)): if f: soft_node_l[i] = None # Add back the hard-constraint nodes and soft-constraints that # didn't fail for n in filter(lambda n: n is not None, node_l + soft_node_l): btor.Assume(n) # If we fail again, then we truly have a problem if btor.Sat() != btor.SAT: # Ensure we clean up x = start_rs_i while x < rs_i: rs = ri.randsets()[x] for f in rs.all_fields(): f.dispose() x += 1 raise Exception("solve failure") else: # Still need to convert assumptions to assertions for n in filter(lambda n: n is not None, node_l + soft_node_l): btor.Assert(n) else: print("Failed constraints:") i = 1 for c in constraint_l: if btor.Failed(c[1]): print("[" + str(i) + "]: " + self.pretty_printer.do_print(c[0], False)) print("[" + str(i) + "]: " + self.pretty_printer.do_print(c[0], True)) i += 1 # Ensure we clean up for rs in ri.randsets(): for f in rs.all_fields(): f.dispose() print("Solve failure") raise Exception("solve failure") else: # Still need to convert assumptions to assertions btor.Assert(*(node_l + soft_node_l)) self.swizzle_randvars(btor, ri, start_rs_i, rs_i, bound_m) # Finalize the value of the field x = start_rs_i while x < rs_i: rs = ri.randsets()[x] for f in rs.all_fields(): f.post_randomize() f.dispose( ) # Get rid of the solver var, since we're done with it x += 1 uc_rand = list(filter(lambda f: f.is_used_rand, ri.unconstrained())) for uf in uc_rand: bounds = bound_m[uf] range_l = bounds.domain.range_l if len(range_l) == 1: # Single (likely domain-based) range uf.set_val(self.randint(range_l[0][0], range_l[0][1])) else: # Most likely an enumerated type # TODO: are there any cases where these could be ranges? idx = self.randint(0, len(range_l) - 1) uf.set_val(range_l[idx][0])
def create_diagnostics(self, active_randsets) -> str: ret = "" btor = Boolector() btor.Set_opt(pyboolector.BTOR_OPT_INCREMENTAL, True) btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, True) diagnostic_constraint_l = [] diagnostic_field_l = [] # First, determine how many randsets are actually failing i = 0 while i < len(active_randsets): rs = active_randsets[i] for f in rs.all_fields(): f.build(btor) # Assume that we can omit all soft constraints, since they # will have already been omitted (?) constraint_l = list(map(lambda c:(c,c.build(btor)), filter(lambda c:not isinstance(c,ConstraintSoftModel), rs.constraints()))) for c in constraint_l: btor.Assume(c[1]) if btor.Sat() != btor.SAT: # Save fields and constraints if the randset doesn't # solve on its own diagnostic_constraint_l.extend(constraint_l) diagnostic_field_l.extend(rs.fields()) i += 1 problem_constraints = [] solving_constraints = [] # Okay, now perform a series of solves to identify # constraints that are actually a problem for c in diagnostic_constraint_l: btor.Assume(c[1]) if btor.Sat() != btor.SAT: # This is a problematic constraint # Save it for later problem_constraints.append(c[0]) else: # Not a problem. Assert it now btor.Assert(c[1]) solving_constraints.append(c[0]) # problem_constraints.append(c[0]) if btor.Sat() != btor.SAT: raise Exception("internal error: system should solve") # Okay, we now have a constraint system that solves, and # a list of constraints that are a problem. We want to # resolve the value of all variables referenced by the # solving constraints so and then display the non-solving # constraints. This will (hopefully) help highlight the # reason for the failure for c in solving_constraints: c.accept(RefFieldsPostRandVisitor()) ret += "Problem Constraints:\n" for i,pc in enumerate(problem_constraints): ret += "Constraint " + str(i+1) + ":\n" ret += ModelPrettyPrinter.print(pc, print_values=True) ret += ModelPrettyPrinter.print(pc, print_values=False) for rs in active_randsets: for f in rs.all_fields(): f.dispose() return ret
def randomize(self, ri : RandInfo, bound_m : Dict[FieldModel,VariableBoundModel]): """Randomize the variables and constraints in a RandInfo collection""" if self.debug > 0: for rs in ri.randsets(): print("RandSet") for f in rs.all_fields(): if f in bound_m.keys(): print(" Field: " + f.fullname + " " + str(bound_m[f].domain.range_l)) for c in rs.constraints(): print(" Constraint: " + self.pretty_printer.do_print(c, show_exp=True)) for uf in ri.unconstrained(): print("Unconstrained: " + uf.name) # Assign values to the unconstrained fields first uc_rand = list(filter(lambda f:f.is_used_rand, ri.unconstrained())) for uf in uc_rand: if self.debug > 0: print("Randomizing unconstrained: " + uf.fullname) bounds = bound_m[uf] range_l = bounds.domain.range_l if len(range_l) == 1: # Single (likely domain-based) range uf.set_val( self.randint(range_l[0][0], range_l[0][1])) else: # Most likely an enumerated type # TODO: are there any cases where these could be ranges? idx = self.randint(0, len(range_l)-1) uf.set_val(range_l[idx][0]) # Lock so we don't overwrite uf.set_used_rand(False) rs_i = 0 start_rs_i = 0 max_fields = 20 while rs_i < len(ri.randsets()): btor = Boolector() self.btor = btor btor.Set_opt(pyboolector.BTOR_OPT_INCREMENTAL, True) btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, True) start_rs_i = rs_i constraint_l = [] # Collect up to max_fields fields to randomize at a time n_fields = 0 while rs_i < len(ri.randsets()): rs = ri.randsets()[rs_i] rs_node_builder = RandSetNodeBuilder(btor) all_fields = rs.all_fields() if self.debug > 0: print("Pre-Randomize: RandSet") for f in all_fields: if f in bound_m.keys(): print(" Field: " + f.fullname + " " + str(bound_m[f].domain.range_l)) for c in rs.constraints(): print(" Constraint: " + self.pretty_printer.do_print(c, show_exp=True, print_values=True)) rs_node_builder.build(rs) n_fields += len(all_fields) constraint_l.extend(list(map(lambda c:(c,c.build(btor),isinstance(c,ConstraintSoftModel)), rs.constraints()))) rs_i += 1 if n_fields > max_fields or rs.order != -1: break for c in constraint_l: try: btor.Assume(c[1]) except Exception as e: from ..visitors.model_pretty_printer import ModelPrettyPrinter print("Exception: " + ModelPrettyPrinter.print(c[0])) raise e soft_node_l = list(map(lambda c:c[1], filter(lambda c:c[2], constraint_l))) node_l = list(map(lambda c:c[1], filter(lambda c:not c[2], constraint_l))) # Perform an initial solve to establish correctness if btor.Sat() != btor.SAT: if len(soft_node_l) > 0: # Try one more time before giving up for i,f in enumerate(soft_node_l): if btor.Failed(f): soft_node_l[i] = None # Add back the hard-constraint nodes and soft-constraints that # didn't fail # for n in filter(lambda n:n is not None, node_l+soft_node_l): for n in filter(lambda n:n is not None, node_l): btor.Assume(n) for n in filter(lambda n:n is not None, soft_node_l): btor.Assume(n) # If we fail again, then we truly have a problem if btor.Sat() != btor.SAT: # Ensure we clean up # active_randsets = [] # x=start_rs_i # while x < rs_i: # rs = ri.randsets()[x] # active_randsets.append(rs) # for f in rs.all_fields(): # f.dispose() # x += 1 active_randsets = [] for rs in ri.randsets(): active_randsets.append(rs) for f in rs.all_fields(): f.dispose() raise SolveFailure( "solve failure", self.create_diagnostics(active_randsets)) # raise SolveFailure( # "solve failure", # self.create_diagnostics(active_randsets)) else: # Still need to convert assumptions to assertions for n in filter(lambda n:n is not None, node_l+soft_node_l): btor.Assert(n) else: # print("Failed constraints:") # i=1 # for c in constraint_l: # if btor.Failed(c[1]): # print("[" + str(i) + "]: " + self.pretty_printer.do_print(c[0], False)) # print("[" + str(i) + "]: " + self.pretty_printer.do_print(c[0], True)) # i+=1 # Ensure we clean up active_randsets = [] for rs in ri.randsets(): active_randsets.append(rs) for f in rs.all_fields(): f.dispose() raise SolveFailure( "solve failure", self.create_diagnostics(active_randsets)) else: # Still need to convert assumptions to assertions btor.Assert(*(node_l+soft_node_l)) self.swizzle_randvars(btor, ri, start_rs_i, rs_i, bound_m) # Finalize the value of the field x = start_rs_i reset_v = DynamicExprResetVisitor() while x < rs_i: rs = ri.randsets()[x] for f in rs.all_fields(): f.post_randomize() f.set_used_rand(False, 0) f.dispose() # Get rid of the solver var, since we're done with it f.accept(reset_v) # for f in rs.nontarget_field_s: # f.dispose() for c in rs.constraints(): c.accept(reset_v) RandSetDisposeVisitor().dispose(rs) x += 1 end = int(round(time.time() * 1000))
def __init__(self, quantized_model, btor=None, verbose=None, config=None): if btor is None: btor = Boolector() btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, 2) self.btor = btor self._debug_list = [] self._verbose = verbose # This setting should yield the best results on average self.config = { "add_bound_constraints": True, "sat_engine_cadical": True, "rebalance_sum": True, "recursive_sum": True, "sort_sum": None, "propagate_bounds": True, "relu_simplify": True, "subsum_elimination": False, # subsub elimination can hurt performance -> better not activate it "min_bits": True, "shift_elimination": True, } # Overwrite default config with argument if not config is None: for k, v in config.items(): self.config[k] = v self._stats = { "constant_neurons": 0, "linear_neurons": 0, "unstable_neurons": 0, "reused_expressions": 0, "partially_stable_neurons": 0, "build_time": 0, "sat_time": 0, "total_time": 0, } self.dense_layers = [] self.quantized_model = quantized_model self._last_layer_signed = quantized_model._last_layer_signed self.quantization_config = quantized_model.quantization_config current_bits = self.quantization_config["input_bits"] for i, l in enumerate(quantized_model.dense_layers): self.dense_layers.append( LayerEncoding( layer_size=l.units, btor=self.btor, bit_width=self.quantization_config["quantization_bits"], frac_bits=self.quantization_config["quantization_bits"] - self.quantization_config["int_bits_activation"], quantization_config=self.quantization_config, signed_output=l.signed_output, )) # Create input vars input_size = quantized_model._input_shape[-1] self.input_layer = LayerEncoding( layer_size=input_size, btor=self.btor, bit_width=self.quantization_config["input_bits"], frac_bits=self.quantization_config["input_bits"] - self.quantization_config["int_bits_input"], quantization_config=self.quantization_config, ) self.input_vars = self.input_layer.vars self.output_vars = self.dense_layers[-1].vars
def randomize(self, ri: RandInfo, bound_m: Dict[FieldModel, VariableBoundModel]): """Randomize the variables and constraints in a RandInfo collection""" if self.solve_info is not None: self.solve_info.n_randsets = len(ri.randsets()) if self.debug > 0: rs_i = 0 while rs_i < len(ri.randsets()): rs = ri.randsets()[rs_i] print("RandSet[%d]" % rs_i) for f in rs.all_fields(): if f in bound_m.keys(): print(" Field: %s is_rand=%s %s" % (f.fullname, str(f.is_used_rand), str(bound_m[f].domain.range_l))) else: print(" Field: %s is_rand=%s (unbounded)" % (f.fullname, str(f.is_used_rand))) for c in rs.constraints(): print(" Constraint: " + self.pretty_printer.do_print(c, show_exp=True)) for c in rs.soft_constraints(): print(" SoftConstraint: " + self.pretty_printer.do_print(c, show_exp=True)) rs_i += 1 for uf in ri.unconstrained(): print("Unconstrained: " + uf.fullname) # Assign values to the unconstrained fields first uc_rand = list(filter(lambda f: f.is_used_rand, ri.unconstrained())) for uf in uc_rand: if self.debug > 0: print("Randomizing unconstrained: " + uf.fullname) bounds = bound_m[uf] range_l = bounds.domain.range_l if len(range_l) == 1: # Single (likely domain-based) range uf.set_val(self.randstate.randint(range_l[0][0], range_l[0][1])) else: # Most likely an enumerated type # TODO: are there any cases where these could be ranges? idx = self.randstate.randint(0, len(range_l) - 1) uf.set_val(range_l[idx][0]) # Lock so we don't overwrite uf.set_used_rand(False) rs_i = 0 start_rs_i = 0 # max_fields = 20 max_fields = 0 while rs_i < len(ri.randsets()): btor = Boolector() self.btor = btor btor.Set_opt(pyboolector.BTOR_OPT_INCREMENTAL, True) btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, True) start_rs_i = rs_i constraint_l = [] soft_constraint_l = [] # Collect up to max_fields fields to randomize at a time n_fields = 0 while rs_i < len(ri.randsets()): rs = ri.randsets()[rs_i] rs_node_builder = RandSetNodeBuilder(btor) all_fields = rs.all_fields() if self.debug > 0: print("Pre-Randomize: RandSet[%d]" % rs_i) for f in all_fields: if f in bound_m.keys(): print(" Field: %s is_rand=%s %s var=%s" % (f.fullname, str(f.is_used_rand), str(bound_m[f].domain.range_l), str(f.var))) else: print(" Field: %s is_rand=%s (unbounded)" % (f.fullname, str(f.is_used_rand))) for c in rs.constraints(): print(" Constraint: " + self.pretty_printer.do_print( c, show_exp=True, print_values=True)) for c in rs.soft_constraints(): print(" SoftConstraint: " + self.pretty_printer.do_print( c, show_exp=True, print_values=True)) if self.solve_info is not None: self.solve_info.n_cfields += len(all_fields) rs_node_builder.build(rs) n_fields += len(all_fields) # constraint_l.extend(list(map(lambda c:(c,c.build(btor),isinstance(c,ConstraintSoftModel)), rs.constraints()))) constraint_l.extend( list(map(lambda c: (c, c.build(btor)), rs.constraints()))) soft_constraint_l.extend( list( map(lambda c: (c, c.build(btor)), rs.soft_constraints()))) # Sort the list in descending order so we know which constraints # to prioritize soft_constraint_l.sort(key=lambda c: c[0].priority, reverse=True) rs_i += 1 if n_fields > max_fields or rs.order != -1: break for c in constraint_l: try: btor.Assume(c[1]) except Exception as e: print("Exception: " + self.pretty_printer.print(c[0])) raise e if self.solve_info is not None: self.solve_info.n_sat_calls += 1 if btor.Sat() != btor.SAT: # If the system doesn't solve with hard constraints added, # then we may as well bail now active_randsets = [] for rs in ri.randsets(): active_randsets.append(rs) for f in rs.all_fields(): f.dispose() if self.solve_fail_debug > 0: raise SolveFailure( "solve failure", self.create_diagnostics(active_randsets)) else: raise SolveFailure( "solve failure", "Solve failure: set 'solve_fail_debug=1' for more details" ) else: # Lock down the hard constraints that are confirmed # to be valid for c in constraint_l: btor.Assert(c[1]) # If there are soft constraints, add these now if len(soft_constraint_l) > 0: for c in soft_constraint_l: try: btor.Assume(c[1]) except Exception as e: from ..visitors.model_pretty_printer import ModelPrettyPrinter print("Exception: " + ModelPrettyPrinter.print(c[0])) raise e if self.solve_info is not None: self.solve_info.n_sat_calls += 1 if btor.Sat() != btor.SAT: # All the soft constraints cannot be satisfied. We'll need to # add them incrementally if self.debug > 0: print( "Note: some of the %d soft constraints could not be satisfied" % len(soft_constraint_l)) for c in soft_constraint_l: btor.Assume(c[1]) if self.solve_info is not None: self.solve_info.n_sat_calls += 1 if btor.Sat() == btor.SAT: if self.debug > 0: print("Note: soft constraint %s (%d) passed" % (self.pretty_printer.print( c[0]), c[0].priority)) btor.Assert(c[1]) else: if self.debug > 0: print("Note: soft constraint %s (%d) failed" % (self.pretty_printer.print( c[0]), c[0].priority)) else: # All the soft constraints could be satisfied. Assert them now if self.debug > 0: print( "Note: all %d soft constraints could be satisfied" % len(soft_constraint_l)) for c in soft_constraint_l: btor.Assert(c[1]) # btor.Sat() x = start_rs_i while x < rs_i: self.swizzler.swizzle(btor, ri.randsets()[x], bound_m) x += 1 # Finalize the value of the field x = start_rs_i reset_v = DynamicExprResetVisitor() while x < rs_i: rs = ri.randsets()[x] for f in rs.all_fields(): f.post_randomize() f.set_used_rand(False, 0) f.dispose( ) # Get rid of the solver var, since we're done with it f.accept(reset_v) # for f in rs.nontarget_field_s: # f.dispose() for c in rs.constraints(): c.accept(reset_v) RandSetDisposeVisitor().dispose(rs) if self.debug > 0: print("Post-Randomize: RandSet[%d]" % x) for f in all_fields: if f in bound_m.keys(): print(" Field: %s %s" % (f.fullname, str(f.val.val))) else: print(" Field: %s (unbounded) %s" % (f.fullname, str(f.val.val))) for c in rs.constraints(): print(" Constraint: " + self.pretty_printer.do_print( c, show_exp=True, print_values=True)) for c in rs.soft_constraints(): print(" SoftConstraint: " + self.pretty_printer.do_print( c, show_exp=True, print_values=True)) x += 1 end = int(round(time.time() * 1000))
def create_diagnostics(self, active_randsets) -> str: btor = Boolector() btor.Set_opt(pyboolector.BTOR_OPT_INCREMENTAL, True) btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, True) model_valid = False diagnostic_constraint_l = [] diagnostic_field_l = [] # First, determine how many randsets are actually failing i = 0 while i < len(active_randsets): rs = active_randsets[i] for f in rs.all_fields(): f.build(btor) # Assume that we can omit all soft constraints, since they # will have already been omitted (?) constraint_l = list( map( lambda c: (c, c.build(btor)), filter(lambda c: not isinstance(c, ConstraintSoftModel), rs.constraints()))) for c in constraint_l: btor.Assume(c[1]) if btor.Sat() != btor.SAT: # Save fields and constraints if the randset doesn't # solve on its own diagnostic_constraint_l.extend(constraint_l) diagnostic_field_l.extend(rs.fields()) i += 1 problem_sets = [] degree = 1 while True: init_size = len(diagnostic_constraint_l) tmp_l = [] ret = self._collect_failing_constraints(btor, diagnostic_constraint_l, 0, degree, tmp_l, problem_sets) if len(diagnostic_constraint_l) == init_size and degree > 3: break else: degree += 1 if Randomizer.EN_DEBUG > 0: print("%d constraints remaining ; %d problem sets" % (len(diagnostic_constraint_l), len(problem_sets))) # Assert the remaining constraints for c in diagnostic_constraint_l: btor.Assert(c[1]) if btor.Sat() != btor.SAT: raise Exception("internal error: system should solve") # Okay, we now have a constraint system that solves, and # a list of constraints that are a problem. We want to # resolve the value of all variables referenced by the # solving constraints so and then display the non-solving # constraints. This will (hopefully) help highlight the # reason for the failure ret = "" for ps in problem_sets: ret += ("Problem Set: %d constraints\n" % len(ps)) for pc in ps: ret += " %s:\n" % SourceInfo.toString(pc[0].srcinfo) ret += " %s" % ModelPrettyPrinter.print(pc[0], print_values=False) pc = [] for c in ps: pc.append(c[0]) lint_r = LintVisitor().lint([], pc) if lint_r != "": ret += "Lint Results:\n" + lint_r for rs in active_randsets: for f in rs.all_fields(): f.dispose() return ret
import os import pyboolector from pyboolector import Boolector, BoolectorException if __name__ == "__main__": try: # Create Boolector instance btor = Boolector() # Enable model generation btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, True) # Create bit-vector sort of size 8 bvsort8 = btor.BitVecSort(8) # Create expressions x = btor.Var(bvsort8, "x") y = btor.Var(bvsort8, "y") zero = btor.Const(0, 8) hundred = btor.Const(100, 8) # 0 < x ult_x = btor.Ult(zero, x) btor.Assert(ult_x) # x <= 100 ulte_x = btor.Ulte(x, hundred) btor.Assert(ulte_x) # 0 < y ult_y = btor.Ult(zero, y) btor.Assert(ult_y) # y <= 100 ulte_y = btor.Ulte(y, hundred) btor.Assert(ulte_y) # x * y mul = btor.Mul(x, y)