class Randomizer(RandIF): """Implements the core randomization algorithm""" EN_DEBUG = False def __init__(self, debug=0): self.pretty_printer = ModelPrettyPrinter() self.debug = debug _state_p = [0,1] _rng = None 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 swizzle_randvars(self, btor : Boolector, ri : RandInfo, start_rs : int, end_rs : int, bound_m : Dict[FieldModel,VariableBoundModel]): # TODO: we must ignore fields that are otherwise being controlled if self.debug > 0: print("--> swizzle_randvars") rand_node_l = [] rand_e_l = [] x=start_rs while x < end_rs: # For each random variable, select a partition with it's known # domain and add the corresponding constraint rs = ri.randsets()[x] field_l = rs.rand_fields() if self.debug > 0: print(" " + str(len(field_l)) + " fields in randset") if len(field_l) == 1: # Go ahead and pick values in the domain, since there # are no other constraints f = field_l[0] if f in bound_m.keys(): f_bound = bound_m[f] if not f_bound.isEmpty(): e = self.create_rand_domain_constraint(f, f_bound) if e is not None: n = e.build(btor) rand_node_l.append(n) rand_e_l.append(e) elif len(field_l) > 0: field_idx = self.randint(0, len(field_l)-1) f = field_l[field_idx] if self.debug > 0: print("Swizzling field " + f.name) if f in bound_m.keys(): f_bound = bound_m[f] if not f_bound.isEmpty(): e = self.create_rand_domain_constraint(f, f_bound) if e is not None: n = e.build(btor) rand_node_l.append(n) rand_e_l.append(e) # btor.Assume(n) else: # It's always possible that this value is already fixed. # Just ignore. # rand_node_l.append(None) pass else: if self.debug > 0: print("Note: no bounds found for field " + f.name) x += 1 if len(rand_node_l) > 0: btor.Assume(*rand_node_l) # btor.Assert(*rand_node_l) if btor.Sat() != btor.SAT: # Remove any failing assumptions if self.debug > 0: print("Randomization constraint failed") n_failed = 0 for i,n in enumerate(rand_node_l): if n is not None and btor.Failed(n): rand_node_l[i] = None n_failed += 1 # Sanity check if n_failed == 0: for e in rand_e_l: print("Constraint: " + ModelPrettyPrinter.print(e)) raise Exception("UNSAT reported, but no failing assertions") # # Re-apply the constraints that succeeded btor.Assert(*filter(lambda n:n is not None, rand_node_l)) if btor.Sat() != btor.SAT: raise Exception("failed to add in randomization (2)") else: if btor.Sat() != btor.SAT: raise Exception("failed to add in randomization") if self.debug > 0: print("<-- swizzle_randvars") def create_rand_domain_constraint(self, f : FieldScalarModel, bound_m : VariableBoundModel)->ExprModel: e = None range_l = bound_m.domain.range_l range_idx = self.randint(0, len(range_l)-1) range = range_l[range_idx] domain = range[1]-range[0] if self.debug > 0: print("create_rand_domain_constraint: " + f.name + " range_idx=" + str(range_idx) + " range=" + str(range)) if domain > 64: r_type = self.randint(0, 3) single_val = self.randint(range[0], range[1]) if r_type >= 0 and r_type <= 2: # range # Pretty simple. Partition and randomize bin_sz_h = 1 if int(domain/128) == 0 else int(domain/128) if r_type == 0: # Center value in bin if single_val+bin_sz_h > range[1]: max = range[1] min = range[1]-2*bin_sz_h elif single_val-bin_sz_h < range[0]: max = range[0]+2*bin_sz_h min = range[0] else: max = single_val+bin_sz_h min = single_val-bin_sz_h elif r_type == 1: # Bin starts at value if single_val+2*bin_sz_h > range[1]: max = range[1] min = range[1]-2*bin_sz_h elif single_val-2*bin_sz_h < range[0]: max = range[0]+2*bin_sz_h min = range[0] else: max = single_val+2*bin_sz_h min = single_val elif r_type == 2: # Bin ends at value if single_val+2*bin_sz_h > range[1]: max = range[1] min = range[1]-2*bin_sz_h elif single_val-2*bin_sz_h < range[0]: max = range[0]+2*bin_sz_h min = range[0] else: max = single_val min = single_val-2*bin_sz_h e = ExprBinModel( ExprBinModel( ExprFieldRefModel(f), BinExprType.Ge, ExprLiteralModel( min, f.is_signed, f.width) ), BinExprType.And, ExprBinModel( ExprFieldRefModel(f), BinExprType.Le, ExprLiteralModel( max, f.is_signed, f.width) ) ) elif r_type == 3: # Single value e = ExprBinModel( ExprFieldRefModel(f), BinExprType.Eq, ExprLiteralModel(single_val, f.is_signed, f.width)) else: val = self.randint(range[0], range[1]) e = ExprBinModel( ExprFieldRefModel(f), BinExprType.Eq, ExprLiteralModel(val, f.is_signed, f.width)) return e def randint(self, low, high): if low > high: tmp = low low = high high = tmp # if Randomizer._rng is None: # Randomizer._rng = random.Random(random.randrange(sys.maxsize)) # return Randomizer._rng.randint(low, high) return random.randint(low, high) def randbits(self, nbits): # if Randomizer._rng is None: # Randomizer._rng = random.Random(random.randrange(sys.maxsize)) # return Randomizer._rng.randint(0, (1<<nbits)-1) return random.randint(0, (1<<nbits)-1) @staticmethod def _next(): # if Randomizer._rng is None: # Randomizer._rng = random.Random(random.randrange(sys.maxsize)) # ret = Randomizer._rng.randint(0, 0xFFFFFFFF) ret = random.randint(0, 0xFFFFFFFF) # ret = (Randomizer._state_p[0] + Randomizer._state_p[1]) & 0xFFFFFFFF # Randomizer._state_p[1] ^= Randomizer._state_p[0] # Randomizer._state_p[0] = (((Randomizer._state_p[0] << 55) | (Randomizer._state_p[0] >> 9)) # ^ Randomizer._state_p[1] ^ (Randomizer._state_p[1] << 14)) # Randomizer._state_p[1] = (Randomizer._state_p[1] << 36) | (Randomizer._state_p[1] >> 28) return ret 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 @staticmethod def do_randomize( field_model_l : List[FieldModel], constraint_l : List[ConstraintModel] = None, debug=0): # All fields passed to do_randomize are treated # as randomizable # if Randomizer._rng is None: # Randomizer._rng = random.Random(random.randrange(sys.maxsize)) # seed = Randomizer._rng.randint(0, (1 << 64)-1) seed = random.randint(0, (1<<64)-1) for f in field_model_l: f.set_used_rand(True, 0) if debug > 0: print("Initial Model:") for fm in field_model_l: print(" " + ModelPrettyPrinter.print(fm)) # First, invoke pre_randomize on all elements for fm in field_model_l: fm.pre_randomize() if constraint_l is None: constraint_l = [] # Collect all variables (pre-array) and establish bounds bounds_v = VariableBoundVisitor() bounds_v.process(field_model_l, constraint_l, False) # TODO: need to handle inline constraints that impact arrays constraints_len = len(constraint_l) for fm in field_model_l: constraint_l.extend(ArrayConstraintBuilder.build( fm, bounds_v.bound_m)) # Now, handle dist constraints DistConstraintBuilder.build(seed, fm) for c in constraint_l: constraint_l.extend(ArrayConstraintBuilder.build( c, bounds_v.bound_m)) # Now, handle dist constraints DistConstraintBuilder.build(seed, c) # If we made changes during array remodeling, # re-run bounds checking on the updated model # if len(constraint_l) != constraints_len: bounds_v.process(field_model_l, constraint_l) if debug > 0: print("Final Model:") for fm in field_model_l: print(" " + ModelPrettyPrinter.print(fm)) for c in constraint_l: print(" " + ModelPrettyPrinter.print(c, show_exp=True)) r = Randomizer(debug=debug) # if Randomizer._rng is None: # Randomizer._rng = random.Random(random.randrange(sys.maxsize)) ri = RandInfoBuilder.build(field_model_l, constraint_l, Randomizer._rng) try: r.randomize(ri, bounds_v.bound_m) finally: # Rollback any constraints we've replaced for arrays for fm in field_model_l: ConstraintOverrideRollbackVisitor.rollback(fm) for fm in field_model_l: fm.post_randomize()
class Randomizer(RandIF): """Implements the core randomization algorithm""" def __init__(self): self.pretty_printer = ModelPrettyPrinter() _state_p = [0, 1] _rng = random.Random() 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 randomize_1(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) for rs in ri.randsets(): # print("RandSet:") # for f in rs.fields(): # print(" Field: " + f.name) # for c in rs.constraints(): # print(" Constraint: " + ModelPrettyPrinter.print(c)) # print("Randset: n_fields=" + str(len(rs.fields()))) btor = Boolector() self.btor = btor btor.Set_opt(pyboolector.BTOR_OPT_INCREMENTAL, True) btor.Set_opt(pyboolector.BTOR_OPT_MODEL_GEN, True) try: for f in rs.all_fields(): f.build(btor) except Exception as e: for c in rs.constraints(): print("Constraint: " + self.pretty_printer.do_print(c)) raise e constraint_l = list( map( lambda c: (c, c.build(btor), isinstance(c, ConstraintSoftModel)), rs.constraints())) 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))) # soft_node_l : [BoolectorNode] = [] # # for c in rs.constraints(): # try: # n = c.build(btor) # if isinstance(c, ConstraintSoftModel): # soft_node_l.append(n) # else: # node_l.append(n) # # btor.Assert(c.build(btor)) # btor.Assume(n) # except Exception as e: # print("Error: The following constraint failed:\n" + str(c)) # raise e # 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 for f in rs.all_fields(): f.dispose() 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 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_1(btor, rs, bound_m) # Finalize the value of the field for f in rs.all_fields(): f.post_randomize() f.dispose( ) # Get rid of the solver var, since we're done with it 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 swizzle_randvars(self, btor: Boolector, ri: RandInfo, start_rs: int, end_rs: int, bound_m: Dict[FieldModel, VariableBoundModel]): # TODO: we must ignore fields that are otherwise being controlled rand_node_l = [] x = start_rs while x < end_rs: # For each random variable, select a partition with it's known # domain and add the corresponding constraint rs = ri.randsets()[x] field_l = rs.fields_l() if len(field_l) == 1: # Go ahead and pick values in the domain, since there # are no other constraints f = field_l[0] e = self.create_single_var_domain_constraint( field_l[0], bound_m[field_l[0]]) if e is not None: n = e.build(btor) rand_node_l.append(n) # btor.Assume(n) else: for f in field_l: if f.is_used_rand and f in bound_m.keys(): f_bound = bound_m[f] if not f_bound.isEmpty(): e = self.create_rand_domain_constraint(f, f_bound) if e is not None: n = e.build(btor) rand_node_l.append(n) # btor.Assume(n) else: # It's always possible that this value is already fixed. # Just ignore. # rand_node_l.append(None) pass x += 1 if len(rand_node_l) > 0: btor.Assume(*rand_node_l) if btor.Sat() != btor.SAT: # Remove any failing assumptions n_failed = 0 for i, n in enumerate(rand_node_l): if n is not None and btor.Failed(n): rand_node_l[i] = None n_failed += 1 # Re-apply the constraints that succeeded btor.Assume(*filter(lambda n: n is not None, rand_node_l)) if btor.Sat() != btor.SAT: raise Exception("failed to add in randomization") def swizzle_randvars_1(self, btor: Boolector, rs: RandInfo, bound_m: Dict[FieldModel, VariableBoundModel]): # TODO: we must ignore fields that are otherwise being controlled # For each random variable, select a partition with it's known # domain and add the corresponding constraint rand_node_l = [] field_l = list(rs.fields()) if len(field_l) == 1: # Go ahead and pick values in the domain, since there # are no other constraints f = field_l[0] e = self.create_single_var_domain_constraint( field_l[0], bound_m[field_l[0]]) if e is not None: n = e.build(btor) rand_node_l.append(n) btor.Assume(n) else: for f in field_l: if f.is_used_rand and f in bound_m.keys(): f_bound = bound_m[f] if not f_bound.isEmpty(): e = self.create_rand_domain_constraint(f, f_bound) if e is not None: n = e.build(btor) rand_node_l.append(n) btor.Assume(n) else: # It's always possible that this value is already fixed. # Just ignore. rand_node_l.append(None) if btor.Sat() != btor.SAT: # Remove any failing assumptions n_failed = 0 for i, n in enumerate(rand_node_l): if n is not None and btor.Failed(n): rand_node_l[i] = None n_failed += 1 if btor.Sat() != btor.SAT: raise Exception("failed to add in randomization") else: btor.Assume(*filter(lambda n: n is not None, rand_node_l)) if btor.Sat() != btor.SAT: raise Exception("failed to add in randomization") def create_rand_domain_constraint( self, f: FieldScalarModel, bound_m: VariableBoundModel) -> ExprModel: e = None range_l = bound_m.domain.range_l # print("create_rand_domain_constraint: " + f.name + " " + str(range_l)) if len(range_l) == 1: domain = range_l[0][1] - range_l[0][0] if domain > 64: r_type = self.randint(0, 3) single_val = self.randint(range_l[0][0], range_l[0][1]) if r_type >= 0 and r_type <= 2: # range # Pretty simple. Partition and randomize bin_sz_h = 1 if int(domain / 128) == 0 else int(domain / 128) if r_type == 0: # Center value in bin if single_val + bin_sz_h > range_l[0][1]: max = range_l[0][1] min = range_l[0][1] - 2 * bin_sz_h elif single_val - bin_sz_h < range_l[0][0]: max = range_l[0][0] + 2 * bin_sz_h min = range_l[0][0] else: max = single_val + bin_sz_h min = single_val - bin_sz_h elif r_type == 1: # Bin starts at value if single_val + 2 * bin_sz_h > range_l[0][1]: max = range_l[0][1] min = range_l[0][1] - 2 * bin_sz_h elif single_val - 2 * bin_sz_h < range_l[0][0]: max = range_l[0][0] + 2 * bin_sz_h min = range_l[0][0] else: max = single_val + 2 * bin_sz_h min = single_val elif r_type == 2: # Bin ends at value if single_val + 2 * bin_sz_h > range_l[0][1]: max = range_l[0][1] min = range_l[0][1] - 2 * bin_sz_h elif single_val - 2 * bin_sz_h < range_l[0][0]: max = range_l[0][0] + 2 * bin_sz_h min = range_l[0][0] else: max = single_val min = single_val - 2 * bin_sz_h e = ExprBinModel( ExprBinModel( ExprFieldRefModel(f), BinExprType.Ge, ExprLiteralModel(min, f.is_signed, f.width)), BinExprType.And, ExprBinModel( ExprFieldRefModel(f), BinExprType.Le, ExprLiteralModel(max, f.is_signed, f.width))) elif r_type == 3: # Single value e = ExprBinModel( ExprFieldRefModel(f), BinExprType.Eq, ExprLiteralModel(single_val, f.is_signed, f.width)) else: val = self.randint(0, domain - 1) e = ExprBinModel(ExprFieldRefModel(f), BinExprType.Eq, ExprLiteralModel(val, f.is_signed, f.width)) else: # domain_bin_ratio = int(len(bound_m.domain.range_l)/len(bound_m.domain_offsets)) # # if domain_bin_ratio <= 1: # # Just pick a single value # print("Should pick single value") # else: # # # print("domain_bin_ratio=" + str(domain_bin_ratio)) # pass # # Multi-range domain pass return e def create_single_var_domain_constraint( self, f: FieldScalarModel, bound_m: VariableBoundModel) -> ExprModel: range_l = bound_m.domain.range_l if len(range_l) == 1: val = self.randint(range_l[0][0], range_l[0][1]) e = ExprBinModel(ExprFieldRefModel(f), BinExprType.Eq, ExprLiteralModel(val, f.is_signed, f.width)) return e else: # domain_bin_ratio = int(len(bound_m.domain.range_l)/len(bound_m.domain_offsets)) domain_bin_ratio = 1 if domain_bin_ratio <= 1: # Just pick a single value off_val = self.randint(0, bound_m.domain_sz - 1) target_val = bound_m.offset2value(off_val) e = ExprBinModel( ExprFieldRefModel(f), BinExprType.Eq, ExprLiteralModel(target_val, f.is_signed, f.width)) return e else: # TODO: For a variable with a small number of bins # relative to the domain the cover, it likely makes # sense to try to place a range within the bin instead # of selecting a single value # print("domain_bin_ratio=" + str(domain_bin_ratio)) pass return None # gd = f.randgen_data # # if gd.bag is not None: # # Pick out of the bag # vi = self.randint(0, len(gd.bag)-1) # e = ExprBinModel( # ExprFieldRefModel(f), # BinExprType.Eq, # ExprLiteralModel(gd.bag[vi], f.is_signed, f.width)) # else: # domain = (gd.max-gd.min+1) # # if domain > 64: # # Bin randomization # bin = self.randint(0, 100) # bin_sz = int(domain/100) # e = ExprBinModel( # ExprBinModel( # ExprFieldRefModel(f), # BinExprType.Ge, # ExprLiteralModel(gd.min+bin_sz*bin, f.is_signed, f.width) # ), # BinExprType.And, # ExprBinModel( # ExprFieldRefModel(f), # BinExprType.Le, # ExprLiteralModel(gd.min+bin_sz*(bin+1)-1, f.is_signed, f.width) # ) # ) # else: # # Select a specific value # off = self.randint(0, domain-1) # e = ExprBinModel( # ExprFieldRefModel(f), # BinExprType.Eq, # ExprLiteralModel(gd.min+off, f.is_signed, f.width) # ) def calc_domain(self, f: FieldScalarModel, btor: Boolector): """Find the reachable bounds of a variable""" gd = f.randgen_data mid = gd.min + (gd.max - gd.min - 1) # Find the minimum # while mid > self.min and mid < self.max: # pass def swizzle_randvars_slice(self, btor, rs): # Form the swizzle expression around bits in the # target randset variables. The resulting expression # enables us to minimize the deviations from the selected # bit values rand_node_l = [] for f in rs.fields(): val = self.randbits(f.width) for i in range(f.width): bit_i = ((val >> i) & 1) n = btor.Eq(btor.Slice(f.var, i, i), btor.Const(bit_i, 1)) rand_node_l.append(n) btor.Assume(*rand_node_l) if btor.Sat() != btor.SAT: # Clear out any failing assumptions # Try one more time before giving up n_failed = 0 for i, f in enumerate(rand_node_l): if btor.Failed(f): rand_node_l[i] = None n_failed += 1 btor.Assume(*filter(lambda n: n is not None, rand_node_l)) if btor.Sat() != btor.SAT: print("Randomization failed") for i, n in enumerate(rand_node_l): if n is not None: if btor.Failed(n): print("Assumption " + str(i) + " failed") raise Exception("solve failure") def minimize(self, expr, min_t, max_t): ret = -1 if min_t == max_t: mid_point = min_t else: mid_point = min_t + int((max_t - min_t + 1) / 2) # print("--> optimize_rand_c: min=" + str(min_t) + " mid_point=" + str(mid_point) + " max=" + str(max_t)) # Push a new constraint scope # self.btor.Push() self.btor.Assume(self.btor.Ulte(expr, self.btor.Const(mid_point, 32))) if self.btor.Sat() == self.btor.SAT: # print(" SAT") if mid_point > 0 and min_t != max_t: # self.btor.Pop() # Continue making the range smaller sub_r = self.minimize(expr, min_t, mid_point - 1) if sub_r == -1: # re-solve, since this is the best we'll do self.btor.Push() self.btor.Sat() ret = mid_point else: # The sub-solved worked out, so take that value ret = sub_r else: ret = mid_point else: # print(" UNSAT") # self.btor.Pop() if mid_point < max_t: # Solve failed, so let's explore the upper portion ret = self.minimize(expr, mid_point + 1, max_t) else: # Dead-end here ret = -1 # print("<-- optimize_rand_c: ret=" + str(ret)) return ret def randint(self, low, high): return Randomizer._rng.randint(low, high) def randbits(self, nbits): return Randomizer._rng.randint(0, (1 << nbits) - 1) @staticmethod def _next(): ret = Randomizer._rng.randint(0, 0xFFFFFFFF) # ret = (Randomizer._state_p[0] + Randomizer._state_p[1]) & 0xFFFFFFFF # Randomizer._state_p[1] ^= Randomizer._state_p[0] # Randomizer._state_p[0] = (((Randomizer._state_p[0] << 55) | (Randomizer._state_p[0] >> 9)) # ^ Randomizer._state_p[1] ^ (Randomizer._state_p[1] << 14)) # Randomizer._state_p[1] = (Randomizer._state_p[1] << 36) | (Randomizer._state_p[1] >> 28) return ret @staticmethod def do_randomize(field_model_l: List[FieldModel], constraint_l: List[ConstraintModel] = None): # All fields passed to do_randomize are treated # as randomizable for f in field_model_l: f.set_used_rand(True, 0) if constraint_l is None: constraint_l = [] # Collect all variables (pre-array) and establish bounds bounds_v = VariableBoundVisitor() bounds_v.process(field_model_l, constraint_l, False) # TODO: need to handle inline constraints that impact arrays constraints_len = len(constraint_l) for fm in field_model_l: constraint_l.extend( ArrayConstraintBuilder.build(fm, bounds_v.bound_m)) # If we made changes during array remodeling, # re-run bounds checking on the updated model # if len(constraint_l) != constraints_len: bounds_v.process(field_model_l, constraint_l) # First, invoke pre_randomize on all elements for fm in field_model_l: fm.pre_randomize() r = Randomizer() ri = RandInfoBuilder.build(field_model_l, constraint_l, Randomizer._rng) try: r.randomize(ri, bounds_v.bound_m) finally: # Rollback any constraints we've replaced for arrays for fm in field_model_l: ConstraintOverrideRollbackVisitor.rollback(fm) for fm in field_model_l: fm.post_randomize()
class Randomizer(RandIF): """Implements the core randomization algorithm""" EN_DEBUG = False def __init__(self, randstate, debug=0, lint=0, solve_fail_debug=0, solve_info=None): self.randstate = randstate self.pretty_printer = ModelPrettyPrinter() self.solve_info = solve_info self.debug = debug if glbl_debug > 0 and glbl_debug > debug: self.debug = glbl_debug self.lint = lint self.solve_fail_debug = solve_fail_debug if glbl_solvefail_debug > 0 and glbl_solvefail_debug > solve_fail_debug: self.solve_fail_debug = glbl_solvefail_debug # self.swizzler = SolveGroupSwizzlerRange(solve_info) self.swizzler = SolveGroupSwizzlerPartsel(randstate, solve_info) _state_p = [0, 1] _rng = None 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_1(self, active_randsets) -> str: ret = "" 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_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]) model_valid = False 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]) model_valid = True # 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 %d: %s\n" % (i, SourceInfo.toString(pc.srcinfo)) 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 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 def _collect_failing_constraints(self, btor, src_constraint_l, idx, max, tmp_l, fail_set_l): ret = False if len(tmp_l) < max: i = idx while i < len(src_constraint_l): tmp_l.append(i) ret = self._collect_failing_constraints( btor, src_constraint_l, i + 1, max, tmp_l, fail_set_l) tmp_l.pop() if ret: src_constraint_l.pop(i) else: i += 1 else: # Assume full set of collected constraints if Randomizer.EN_DEBUG: print("Assume: " + str(tmp_l)) for c in tmp_l: btor.Assume(src_constraint_l[c][1]) if btor.Sat() != btor.SAT: # Set failed. Add to fail_set fail_s = [] for ci in tmp_l: fail_s.append(src_constraint_l[ci]) fail_set_l.append(tuple(fail_s)) ret = True return ret @staticmethod def do_randomize(randstate, srcinfo: SourceInfo, field_model_l: List[FieldModel], constraint_l: List[ConstraintModel] = None, debug=0, lint=0, solve_fail_debug=0): if profile_on(): solve_info = SolveInfo() solve_info.totaltime = time.time() randomize_start(srcinfo, field_model_l, constraint_l) else: solve_info = None clear_soft_priority = ClearSoftPriorityVisitor() for f in field_model_l: f.set_used_rand(True, 0) clear_soft_priority.clear(f) if debug > 0: print("Initial Model:") for fm in field_model_l: print(" " + ModelPrettyPrinter.print(fm)) # First, invoke pre_randomize on all elements for fm in field_model_l: fm.pre_randomize() if constraint_l is None: constraint_l = [] for c in constraint_l: clear_soft_priority.clear(c) # Collect all variables (pre-array) and establish bounds bounds_v = VariableBoundVisitor() bounds_v.process(field_model_l, constraint_l, False) # TODO: need to handle inline constraints that impact arrays constraints_len = len(constraint_l) for fm in field_model_l: constraint_l.extend( ArrayConstraintBuilder.build(fm, bounds_v.bound_m)) # Now, handle dist constraints DistConstraintBuilder.build(randstate, fm) for c in constraint_l: constraint_l.extend( ArrayConstraintBuilder.build(c, bounds_v.bound_m)) # Now, handle dist constraints DistConstraintBuilder.build(randstate, c) # If we made changes during array remodeling, # re-run bounds checking on the updated model # if len(constraint_l) != constraints_len: bounds_v.process(field_model_l, constraint_l) if debug > 0: print("Final Model:") for fm in field_model_l: print(" " + ModelPrettyPrinter.print(fm)) for c in constraint_l: print(" " + ModelPrettyPrinter.print(c, show_exp=True)) # if lint > 0: # LintVisitor().lint( # field_model_l, # constraint_l) r = Randomizer(randstate, solve_info=solve_info, debug=debug, lint=lint, solve_fail_debug=solve_fail_debug) # if Randomizer._rng is None: # Randomizer._rng = random.Random(random.randrange(sys.maxsize)) ri = RandInfoBuilder.build(field_model_l, constraint_l, Randomizer._rng) try: r.randomize(ri, bounds_v.bound_m) finally: # Rollback any constraints we've replaced for arrays if solve_info is not None: solve_info.totaltime = int( (time.time() - solve_info.totaltime) * 1000) randomize_done(srcinfo, solve_info) for fm in field_model_l: ConstraintOverrideRollbackVisitor.rollback(fm) for fm in field_model_l: fm.post_randomize()