def __call__(self, lk, check_paths): v = Verifier(lk, Backend()) v.add_constraint(v.fvar() > 5.0) v.add_constraint( z3.PbLe([(v.xvar(fid).get(), 1) for fid in v.instance(0).feat_ids()], 50)) return v
def find_max_satisfiable_rule(self): """ Build a model that satisfies as many soft clauses as possible using MAX-SMT """ self.threshold_open = z3.Real('t') self.threshold_listen = z3.Real('u') t = self.threshold_open u = self.threshold_listen self.solver.add(0.0 < t) self.solver.add(t <= 1.0) self.solver.add(0.0 < u) self.solver.add(u <= 1.0) for run in range(len(self.belief_in_runs)): for bel, belief in enumerate(self.belief_in_runs[run]): soft = z3.Bool('b_{}_{}'.format(run, bel)) self.soft_constr_open.append(DummyVar(soft, run, bel, 1)) formula = z3.If(belief[0] > belief[1], belief[0] >= t, belief[1] >= t) if self.actions_in_runs[run][bel] != 0 : self.solver.add(z3.Or(soft, formula)) else: self.solver.add(z3.Or(soft, z3.Not(formula))) soft = z3.Bool('c_{}_{}'.format(run, bel)) self.soft_constr_listen.append(DummyVar(soft, run, bel, 2)) formula = z3.If(belief[0] > belief[1], belief[0] <= u, belief[1] <= u) if self.actions_in_runs[run][bel] == 0 : self.solver.add(z3.Or(soft, formula)) else: self.solver.add(z3.Or(soft, z3.Not(formula))) self.solver.add(self.threshold_open > 0.9) low_threshold = 0 total_soft_constr = len(self.soft_constr_open) + len(self.soft_constr_listen) high_threshold = len(self.soft_constr_open) + len(self.soft_constr_listen) final_threshold = -1 best_model = [] while low_threshold <= high_threshold: self.solver.push() threshold = (low_threshold + high_threshold) // 2 self.solver.add(z3.PbLe([(soft.literal, 1) for soft in (self.soft_constr_open+self.soft_constr_listen)], threshold)) result = self.solver.check() if result == z3.sat: final_threshold = threshold best_model = self.solver.model() high_threshold = threshold - 1 else: low_threshold = threshold + 1 self.solver.pop() return best_model
def build_north_south_rule(self): """ Build a rule for north or south """ c = z3.Real('valuable_confidence') self.thresholds[2].append(c) self.solver.add(c >= 0.0) self.solver.add(c <= 1.0) self.solver.add(c >= self.sample_confidence) ## build soft clauses for i in range(0, len(self.beliefs)): bel = self.beliefs[i] act = self.actions[i] pos = self.positions[i] run = self.runs[i] step = self.steps[i] collected = self.collected[i] # generate boolean var for soft constraints soft = z3.Bool('b_north_south_{}'.format(i)) self.soft_constr[2].append(DummyVar(soft, 2, run, step)) if act != 'north' and act != 'south': self.solver.add(z3.Or(soft, True)) continue if act == 'north': subrules = [] for r in self.rocks: sub = z3.And(pos[1] < r.y, collected[r.num] == 0, bel[r.num] >= c) subrules.append(sub) formula = z3.Or(subrules) self.solver.add(z3.Or(soft, formula)) else: subrules = [] for r in self.rocks: sub = z3.And(pos[1] > r.y, collected[r.num] == 0, bel[r.num] >= c) subrules.append(sub) formula = z3.Or(subrules) self.solver.add(z3.Or(soft, formula)) # solve MAX-SMT problem low_threshold = 0 high_threshold = len(self.soft_constr[2]) final_threshold = -1 best_model = [] while low_threshold <= high_threshold: self.solver.push() threshold = (low_threshold + high_threshold) // 2 #Pble pseudo boolean less equal self.solver.add( z3.PbLe([(soft.literal, 1) for soft in self.soft_constr[1]], threshold)) result = self.solver.check() if result == z3.sat: final_threshold = threshold best_model = self.solver.model() high_threshold = threshold - 1 else: low_threshold = threshold + 1 self.solver.pop() ## build tight bounds model = best_model # fix dummy variables for soft in self.soft_constr[2]: if model[soft.literal] == True: self.solver.add(soft.literal) elif model[soft.literal] == False: self.solver.add(z3.Not(soft.literal)) #self.solver.minimize(z3.Sum(u1, m1, -v1, -n1, u2, m2, -v2, -n2)) # check if SAT or UNSAT result = self.solver.check() if result != z3.sat: print("unsatisfiable") return model = self.solver.model() ## generate 1000 random points inside the rule #rule_points = [[to_real(model[t])]] print( 'move north or south if confidence of treasure is >={:.3f}'.format( to_real(model[c]))) print('fail to satisfy {} out of {} steps'.format( final_threshold, len(self.steps)))
def build_check_rule(self): """ Build a rule for check 1..n """ u1 = z3.Real('u1_sample') self.thresholds[1].append(u1) self.solver.add(0.0 <= u1) self.solver.add(u1 <= 1.0) v1 = z3.Real('v1_sample') self.thresholds[1].append(v1) self.solver.add(0.0 <= v1) self.solver.add(v1 <= 1.0) m1 = z3.Real('m1_sample') self.thresholds[1].append(m1) self.solver.add(m1 >= 0.0) n1 = z3.Real('n1_sample') self.thresholds[1].append(n1) self.solver.add(n1 >= 0.0) self.solver.add(v1 < u1) self.solver.add(n1 <= m1) #u2 = z3.Real('u2_sample') #self.thresholds[1].append(u2) #self.solver.add(0.0 <= u2) #self.solver.add(u2 <= 1.0) #v2 = z3.Real('v2_sample') #self.thresholds[1].append(v2) #self.solver.add(0.0 <= v2) #self.solver.add(v2 <= 1.0) #m2 = z3.Real('m2_sample') #self.thresholds[1].append(m2) #self.solver.add(m2 >= 0.0) #n2 = z3.Real('n2_sample') #self.thresholds[1].append(n2) #self.solver.add(n2 >= 0.0) #self.solver.add(v2 < u2) #self.solver.add(n2 + 1 <= m2) #self.solver.add(m1 <= n2) #self.solver.add(m2 <= 8) ## hard constraint, they must be be specified by hand in this version ## e.g: x_1 >= 0.9 ## build soft clauses for i in range(0, len(self.beliefs)): bel = self.beliefs[i] act = self.actions[i] pos = self.positions[i] run = self.runs[i] step = self.steps[i] collected = self.collected[i] # generate boolean var for soft constraints soft = z3.Bool('b_check_{}'.format(i)) self.soft_constr[1].append(DummyVar(soft, 1, run, step)) if act == 'north' or act == 'south' or act == 'east' or act == 'west' or act == 'sample': self.solver.add(z3.Or(soft, True)) continue c = int(act.split()[1]) r = self.rocks[c] # add the rule formula = z3.Or( z3.And( euclidean_distance(pos[0], pos[1], r.x, r.y) >= n1, euclidean_distance(pos[0], pos[1], r.x, r.y) <= m1, bel[c] <= u1, bel[c] >= v1), #z3.And( # euclidean_distance(pos[0], pos[1], r.x, r.y) >= n2, # euclidean_distance(pos[0], pos[1], r.x, r.y) <= m2, # bel[c] <= u2, # bel[c] >= v2 # ) ) self.solver.add(z3.Or(soft, formula)) # solve MAX-SMT problem low_threshold = 0 high_threshold = len(self.soft_constr[1]) final_threshold = -1 best_model = [] while low_threshold <= high_threshold: self.solver.push() threshold = (low_threshold + high_threshold) // 2 #Pble pseudo boolean less equal self.solver.add( z3.PbLe([(soft.literal, 1) for soft in self.soft_constr[1]], threshold)) result = self.solver.check() if result == z3.sat: final_threshold = threshold best_model = self.solver.model() high_threshold = threshold - 1 else: low_threshold = threshold + 1 self.solver.pop() ## build tight bounds model = best_model # fix dummy variables for soft in self.soft_constr[1]: if model[soft.literal] == True: self.solver.add(soft.literal) elif model[soft.literal] == False: self.solver.add(z3.Not(soft.literal)) self.solver.minimize(z3.Sum(u1, m1, -v1, -n1)) #self.solver.minimize(z3.Sum(u1, m1, -v1, -n1, u2, m2, -v2, -n2)) # check if SAT or UNSAT result = self.solver.check() if result != z3.sat: print("unsatisfiable") return model = self.solver.model() ## generate 1000 random points inside the rule #rule_points = [[to_real(model[t])]] print( 'check when: distance [{:.3f}, {:.3f}] and belief of valuable rock in [{:.3f}, {:.3f}]' .format(to_real(model[n1]), to_real(model[m1]), to_real(model[v1]), to_real(model[u1]))) #print('check when: distance [{:.3f}, {:.3f}] and belief of valuable rock in [{:.3f}, {:.3f}] OR distance [{:.3f}, {:.3f}] and belief of valuable rock in [{:.3f}, {:.3f}]'.format(to_real(model[n1]), to_real(model[m1]), to_real(model[v1]), to_real(model[u1]), to_real(model[n2]), to_real(model[m2]), to_real(model[v2]), to_real(model[u2]))) print('fail to satisfy {} out of {} steps'.format( final_threshold, len(self.steps)))
def build_sample_rule(self): """ Build a rule for sampling """ # enforce probability axioms t = z3.Real('t_sample') self.thresholds[0].append(t) self.solver.add(0.0 <= t) self.solver.add(t <= 1.0) # hard constraint, they must be be specified by hand in this version # e.g: x_1 >= 0.9 #self.solver.add(t > 0.6) # build soft clauses for i in range(0, len(self.beliefs)): bel = self.beliefs[i] act = self.actions[i] pos = self.positions[i] run = self.runs[i] step = self.steps[i] collected = self.collected[i] # generate boolean var for soft constraints soft = z3.Bool('b_sample_{}'.format(i)) self.soft_constr[0].append(DummyVar(soft, 0, run, step)) # add the rule subrules = [] for r in self.rocks: sub = z3.And(pos[0] == r.x, pos[1] == r.y, collected[r.num] == 0, bel[r.num] >= t) subrules.append(sub) formula = z3.Or(subrules) if act != 'sample': formula = z3.Not(formula) self.solver.add(z3.Or(soft, formula)) # solve MAX-SMT problem low_threshold = 0 high_threshold = len(self.soft_constr[0]) final_threshold = -1 best_model = [] while low_threshold <= high_threshold: self.solver.push() threshold = (low_threshold + high_threshold) // 2 #Pble pseudo boolean less equal self.solver.add( z3.PbLe([(soft.literal, 1) for soft in self.soft_constr[0]], threshold)) result = self.solver.check() if result == z3.sat: final_threshold = threshold best_model = self.solver.model() high_threshold = threshold - 1 else: low_threshold = threshold + 1 self.solver.pop() # build tight bounds model = best_model # fix dummy variables for soft in self.soft_constr[0]: if model[soft.literal] == True: self.solver.add(soft.literal) elif model[soft.literal] == False: self.solver.add(z3.Not(soft.literal)) self.solver.maximize(t) # check if SAT or UNSAT result = self.solver.check() if result != z3.sat: print("unsatisfiable") return model = self.solver.model() # generate 1000 random points inside the rule rule_points = [[to_real(model[t])]] print('sample if in position and confidence >= {}'.format( to_real(model[t]))) self.sample_confidence = to_real(model[t]) print('fail to satisfy {} out of {} steps'.format( final_threshold, len(self.steps))) ## Hellinger distance of unsatisfiable steps failed_rules = [] Hellinger_min = [] for num, soft in enumerate(self.soft_constr[0]): if model[soft.literal] == False or self.actions[num] != 'sample': continue failed_rules.append(num) pos = self.positions[num] rock = self.rock_number(pos[0], pos[1]) P = [self.beliefs[num][rock]] hel_dst = [Hellinger_distance(P, Q) for Q in rule_points] Hellinger_min.append(min(hel_dst)) # print unsatisfiable steps in decreasing order of hellinger distance print('Unsatisfiable steps:') for x, soft, hel in [[ x, self.soft_constr[0][x], h ] for h, x in sorted(zip(Hellinger_min, failed_rules), key=lambda pair: pair[0], reverse=True)]: if hel > self.threshold: print('ANOMALY: ', end='') pos = self.positions[x] rock = self.rock_number(pos[0], pos[1]) print( 'run {} step {}: action {} with belief of valuable rock = {:.3f} --- Hellinger = {}' .format(soft.run, soft.step, self.actions[x], self.beliefs[x][rock], hel)) ## Hellinger distance of unsatisfiable steps for num, soft in enumerate(self.soft_constr[0]): if model[soft.literal] == False or self.actions[num] == 'sample': continue pos = self.positions[num] rock = self.rock_number(pos[0], pos[1]) print( 'run {} step {}: action {} with belief of valuable rock = {:.3f}' .format(soft.run, soft.step, self.actions[num], self.beliefs[num][rock]))
def schedule(nurses, surgeries, monthTable, clientTable, monthInfo, surgeryTimeTable): solver = z3.Solver() grid = dict() result = dict() for date in clientTable.keys(): # night nightNurses = list() for groupi in range(1, groupNumPerNight + 1): for nuri in range(1, nurseNumPerGroup + 1): value = z3.Int("night_%sgroup_%dnur_%d" % (date, groupi, nuri)) grid[(date, groupi, nuri)] = value nightNurses.append(value) # constraint: make sure the nurses in night are the same as monthTable solver.add(value == int(monthTable[date][groupi - 1][nuri - 1])) # surgery for surgeryID in clientTable[date]: nightAndDayNurses = list(nightNurses) # nightAndDayNurses = [value for value in nightNurses] for nurseType in nurseTypes: value = z3.Int("day_%ssid_%stype_%s" % (date, surgeryID, nurseType)) grid[(date, surgeryID, nurseType)] = value # department of surgery nurseIDs = clientTable[date][surgeryID] surgery = surgeries[surgeryID] orListForDepartment = list() # constraint: make sure all of the nurses come from client for nurseID in nurseIDs: nurse = nurses[nurseID] if matchDepartment(surgery, nurse): # constraint: make sure the department of nurse matches with surgery orListForDepartment.append( z3.Or(value == int(nurseID))) # constraint: make sure the department of nurse matches with surgery # constraint: make sure all of the nurses come from client solver.add(z3.Or(orListForDepartment)) nightAndDayNurses.append(value) # constraint: make sure nurses working for day are not working for night solver.add(z3.Distinct(nightAndDayNurses)) # solver.add(z3.Eqel) # constraint: make sure the number of surgeries is limited by work hours for nurseID in nurses.keys(): for date in clientTable.keys(): dayNursesConstraint = list() for surgeryID in clientTable[date]: for nurseType in nurseTypes: value = grid[(date, surgeryID, nurseType)] dayNursesConstraint.append((value == int(nurseID), 1)) #<type 'unicode'> if nurses[nurseID].is_pregnant == "true": solver.add(z3.PbLe(dayNursesConstraint, 1)) else: solver.add(z3.PbLe(dayNursesConstraint, 1)) # # constraint: make sure nurses are different in the same time # for surIDs in surgeryTimeTable : # sameTimeNurses = list() # for surID in surIDs : # for nurseType in nurseTypes : # value = grid[(surgeries[surID].date, surID, nurseType)] # sameTimeNurses.append(value) # # constraint: make sure nurses are different in the same time # solver.add(z3.Distinct(sameTimeNurses)) # check sat if solver.check() != z3.sat: print "unsat" return None else: print "sat" # get the model model = solver.model() # get the result for date in clientTable.keys(): dateTable = dict() nightNurses = list() for groupi in range(1, groupNumPerNight + 1): for nuri in range(1, nurseNumPerGroup + 1): nurseID = str(model[grid[(date, groupi, nuri)]].as_long()) nightNurses.append(nurseID) # assert assert nurseID == monthTable[date][groupi - 1][nuri - 1] dateTable["night"] = nightNurses dayTable = dict() for surgeryID in clientTable[date]: surgeryNurses = dict() for nurseType in nurseTypes: surgeryNurses[nurseType] = str( model[grid[date, surgeryID, nurseType]].as_long()) # print model[grid[date, surgeryID, nurseType]].as_long() # print nurses[str(surgeryNurses[nurseType])].priority # constraint: make sure the qualification of roving nurse is higher than instrument nurse if nurses[surgeryNurses["instrument"]].priority > nurses[ surgeryNurses["roving"]].priority: temp = surgeryNurses["instrument"] surgeryNurses["instrument"] = surgeryNurses["roving"] surgeryNurses["roving"] = temp assert nurses[surgeryNurses["instrument"]].priority <= nurses[ surgeryNurses["roving"]].priority dayTable[surgeryID] = surgeryNurses dateTable["day"] = dayTable result[date] = dateTable return result pass
def atMostOne(problem, varList): # constrains at most one of the vars in the list to be true problem.add(z3.PbLe([(v, 1) for v in varList], 1))
def test_mnist_multi_instance(self): at = AddTree.read(f"tests/models/xgb-mnist-yis0-easy.json") dt = DomTree([(at, {}), (at, {})]) l0 = dt.get_leaf(dt.tree().root()) v = Verifier(l0, Backend()) v.add_all_trees(0) v.add_all_trees(1) v.add_constraint(v.fvar(0) > 5.0) # it is with high certainty X v.add_constraint(v.fvar(1) < -5.0) # it is with high certainty not X pbeq = [] for feat_id in AddTreeFeatureTypes(at).feat_ids(): bvar_name = f"b{feat_id}" v.add_bvar(bvar_name) bvar = v.bvar(bvar_name) xvar1 = v.xvar(feat_id, 0) xvar2 = v.xvar(feat_id, 1) v.add_constraint( z3.If(bvar.get(), xvar1.get() != xvar2.get(), xvar1.get() == xvar2.get())) pbeq.append((bvar.get(), 1)) N = 4 v.add_constraint(z3.PbLe(pbeq, N)) # at most N variables differ count = 0 uniques = set() img1_prev, img2_prev = None, None while count < 10: check = v.check() if not check.is_sat(): print("UNSAT") break model = v.model() img1 = np.zeros((28, 28)) img2 = np.zeros((28, 28)) hash1 = 127 hash2 = 91 for fid, x in model[0]["xs"].items(): p = np.unravel_index(fid, (28, 28)) if x is not None: img1[p[1], p[0]] = x hash1 = hash((hash1, fid, x)) for fid, x in model[1]["xs"].items(): p = np.unravel_index(fid, (28, 28)) if x is not None: img2[p[1], p[0]] = x hash2 = hash((hash2, fid, x)) uniques.add(hash((hash1, hash2))) if count > 0: diff1 = abs(img1 - img1_prev).sum() diff2 = abs(img2 - img2_prev).sum() print("mnist_multi_instance: norm difference:", diff1, diff2) self.assertGreater(diff1, 0.0) self.assertGreater(diff2, 0.0) img1_prev, img2_prev = img1, img2 # Ensure that the different pixels have different values in the next iteration # We do not care about the other pixels fam = v.model_family(model) fam_diff0 = {} fam_diff1 = {} for n, b in model["bs"].items(): if not b: continue i = int(n[1:]) p = np.unravel_index(i, (28, 28)) print("different pixel (bvar):", i, p, model[0]["xs"][i], model[1]["xs"][i]) if i in fam[0]: fam_diff0[i] = fam[0][i] if i in fam[1]: fam_diff1[i] = fam[1][i] v.add_constraint( not_in_domain_constraint(v, fam_diff0, 0) & not_in_domain_constraint(v, fam_diff1, 1)) count += 1 print("iteration", count, "uniques", len(uniques)) if count % 100 != 0: continue fig, (ax1, ax2) = plt.subplots(1, 2) ax1.imshow(img1, vmin=0, vmax=255) ax2.imshow(img2, vmin=0, vmax=255) ax1.set_title("instance 1: f={:.3f}".format(model[0]["f"])) ax2.set_title("instance 2: f={:.3f}".format(model[1]["f"])) for n, b in model["bs"].items(): if not b: continue i = int(n[1:]) p = np.unravel_index(i, (28, 28)) ax1.scatter([p[0]], [p[1]], marker=".", color="r") ax2.scatter([p[0]], [p[1]], marker=".", color="r") plt.show() self.assertEqual(count, 10) self.assertEqual(len(uniques), 10)
def to_z3(self, ctx): args = list(map(lambda v: (ctx.z3var(v), 1), self._vars)) return z3.PbLe(args, self._n)
def solve(puzzle: Puzzle, forced_rects: Set[Rect] = frozenset(), clue_constraints: str = 'hard', cover_constraints: str = 'exact', corner_constraints: str = 'hard', reflex_three_corners: bool = False) -> Iterator[List[Rect]]: rect_to_var: Dict[Rect, z3.Bool] = {} # Each cell is covered by exactly one rect. cell_to_rects: Dict[Point, z3.Bool] = {c: list() for c in puzzle.cells} # Each clue is satisfied by exactly one rect (of the right shape). clue_to_rects: Dict[Point, z3.Bool] = {c: list() for c in puzzle.clues.keys()} # Maps cells to rects having a there, for tracking four-corner violations. # The values may be empty (but most won't be). ul_to_rects: Dict[Point, z3.Bool] = {c: list() for c in puzzle.cells} ur_to_rects: Dict[Point, z3.Bool] = {c: list() for c in puzzle.cells} ll_to_rects: Dict[Point, z3.Bool] = {c: list() for c in puzzle.cells} lr_to_rects: Dict[Point, z3.Bool] = {c: list() for c in puzzle.cells} for r1 in range(puzzle.rmax): for c1 in range(puzzle.cmax): for r2 in range(r1, puzzle.rmax): for c2 in range(c1, puzzle.cmax): width, height = c2 - c1 + 1, r2 - r1 + 1 # inclusive rect = Rect(r1, c1, height, width) rect_cells = { Point(r, c) for r in range(r1, r2 + 1) for c in range(c1, c2 + 1) } # Depending on where the violation was, we may be able to # break the r2 loop early for both of these checks. if not rect_cells <= puzzle.cells: if rect in forced_rects: raise RuntimeError( 'forced rect {} contains holes {}'.format( rect, rect_cells - puzzle.cells)) break rect_clues = rect_cells & puzzle.clues.keys() if len(rect_clues) > 1: if rect in forced_rects: raise RuntimeError( 'forced rect {} contains multiple clues at {}'. format(rect, rect_clues)) break if len(rect_clues) == 0: if rect in forced_rects: raise RuntimeError( 'forced rect {} contains no clues'.format( rect)) continue # expanding the rect may add a clue clue_cell = rect_clues.pop() clue = puzzle.clues[clue_cell] expected_clue = Clue.PLUS if width == height else Clue.VERT if width < height else Clue.HORIZ if clue != expected_clue and clue_constraints == 'hard': if rect in forced_rects: raise RuntimeError( 'forced rect {} contains a {}, but is shaped for a {}' .format(rect, clue, expected_clue)) continue var = z3.Bool('{},{},{},{}'.format(r1, c1, height, width)) rect_to_var[rect] = var for c in rect_cells: cell_to_rects[c].append(var) clue_to_rects[clue_cell].append(var) ul_to_rects[Point(r1, c1)].append(var) ur_to_rects[Point(r1, c2)].append(var) ll_to_rects[Point(r2, c1)].append(var) lr_to_rects[Point(r2, c2)].append(var) missing_forced_rects = forced_rects - rect_to_var.keys() if missing_forced_rects: # We could add a command-line flag to disable pruning to get a # better error message here. raise RuntimeError( 'forced rects {} were pruned'.format(missing_forced_rects)) for cell, rects in cell_to_rects.items(): if not rects: print('cell', cell, 'has no covering rects') for clue_cell, rects in clue_to_rects.items(): if not rects: print('clue', puzzle.clues[clue_cell], 'in', clue_cell, 'has no candidate rects') solver = z3.Optimize() for c in puzzle.cells: if c in clue_to_rects and clue_constraints == 'hard': solver.add(z3.PbEq([(r, 1) for r in clue_to_rects[c]], 1)) elif cover_constraints == 'exact': solver.add(z3.PbEq([(r, 1) for r in cell_to_rects[c]], 1)) elif cover_constraints == 'subset': solver.add(z3.PbLe([(r, 1) for r in cell_to_rects[c]], 1)) solver.add_soft(z3.PbGe([(r, 1) for r in cell_to_rects[c]], 1), 1, 'cover') elif cover_constraints == 'superset': solver.add_soft(z3.PbLe([(r, 1) for r in cell_to_rects[c]], 1), 1, 'cover') solver.add(z3.PbGe([(r, 1) for r in cell_to_rects[c]], 1)) elif cover_constraints == 'incomparable': solver.add_soft(z3.PbEq([(r, 1) for r in cell_to_rects[c]], 1), 1, 'cover') else: raise AssertionError('bad cover_constraints: ' + cover_constraints) if corner_constraints != 'ignore': # skip the loop if we wouldn't add anyway for c in puzzle.cells: for r1 in lr_to_rects.get(c, []): for r2 in ll_to_rects.get(Point(c.r, c.c + 1), []): for r3 in ur_to_rects.get(Point(c.r + 1, c.c), []): for r4 in ul_to_rects.get(Point(c.r + 1, c.c + 1), []): if corner_constraints == 'hard': solver.add( z3.PbLe([(r1, 1), (r2, 1), (r3, 1), (r4, 1)], 3)) elif corner_constraints == 'soft': solver.add_soft( z3.PbLe([(r1, 1), (r2, 1), (r3, 1), (r4, 1)], 3), 1, 'corner') else: raise AssertionError( 'bad corner_constraints: ' + corner_constraints) if reflex_three_corners: holes = [ Point(r, c) for r in range(puzzle.rmax) for c in range(puzzle.cmax) if Point(r, c) not in puzzle.cells ] for c in holes: for r2 in ll_to_rects.get(Point(c.r, c.c + 1), []): for r3 in ur_to_rects.get(Point(c.r + 1, c.c), []): for r4 in ul_to_rects.get(Point(c.r + 1, c.c + 1), []): if corner_constraints == 'hard': solver.add( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2)) elif corner_constraints == 'soft': solver.add_soft( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2), 1, 'corner') else: raise AssertionError( 'bad corner_constraints: ' + corner_constraints) for r2 in lr_to_rects.get(Point(c.r, c.c - 1), []): for r3 in ur_to_rects.get(Point(c.r + 1, c.c - 1), []): for r4 in ul_to_rects.get(Point(c.r + 1, c.c), []): if corner_constraints == 'hard': solver.add( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2)) elif corner_constraints == 'soft': solver.add_soft( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2), 1, 'corner') else: raise AssertionError( 'bad corner_constraints: ' + corner_constraints) for r2 in lr_to_rects.get(Point(c.r - 1, c.c), []): for r3 in ll_to_rects.get(Point(c.r - 1, c.c + 1), []): for r4 in ul_to_rects.get(Point(c.r, c.c + 1), []): if corner_constraints == 'hard': solver.add( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2)) elif corner_constraints == 'soft': solver.add_soft( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2), 1, 'corner') else: raise AssertionError( 'bad corner_constraints: ' + corner_constraints) for r2 in lr_to_rects.get(Point(c.r - 1, c.c - 1), []): for r3 in ll_to_rects.get(Point(c.r - 1, c.c), []): for r4 in ur_to_rects.get(Point(c.r, c.c - 1), []): if corner_constraints == 'hard': solver.add( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2)) elif corner_constraints == 'soft': solver.add_soft( z3.PbLe([(r2, 1), (r3, 1), (r4, 1)], 2), 1, 'corner') else: raise AssertionError( 'bad corner_constraints: ' + corner_constraints) if forced_rects: solver.add(z3.And(list(rect_to_var[r] for r in forced_rects))) while solver.check() == z3.sat: model = solver.model() soln: List[Rect] = [] blockers = [] for d in model.decls(): if z3.is_true(model[d]): soln.append(str_to_rect(d.name())) # Build a constraint that prevents this model from being returned again. # https://stackoverflow.com/a/11869410/3614835 blockers.append(d() != model[d]) soln.sort() yield soln solver.add(z3.Or(blockers))
def __init__(self, bool_expressions: Sequence[expr.BooleanExpression], weights: Sequence[float], value: float): super().__init__(expr.WeightedSum(bool_expressions, weights), expr.NumericValue(value)) self.z3_expr = z3.PbLe([(e.get_z3(), w) for (e, w) in zip(bool_expressions, weights)], value)
def find_max_satisfiable_rule(self, rule_num): """ Build a model that satisfies as many soft clauses as possible using MAX-SMT """ print('Find maximum number of satisfiable step in rule {}'.format( rule_num)) rule = self.rules[rule_num] # enforce probability axioms for c in range(len(rule.constraints)): # constraint in rule self.thresholds[rule_num].append([None, None, None]) for s in range(3): # state in constraint # TODO 1: questo va tolto e spostato/generalizzato fuori t = z3.Real('t_r{}_c{}_state{}'.format(rule_num, c, s)) self.thresholds[rule_num][c][s] = t # each threshold is a probability and must have a value # bethween 0 and 1 self.solver.add(0.0 < t) self.solver.add(t <= 1.0) # the sum of the probability on the three states must be 1 prob_sum = z3.Sum(self.thresholds[rule_num][c]) self.solver.add(prob_sum == 1.0) # hard constraint, they must be be specified by hand in this version # e.g: x_1 >= 0.9 # TODO 3: usare le variabili dichiarate per esprimere hard-constraint # e.g. rs.add_hard_constraint(x >= 0.7) # TODO 4: rimuovere codice specifico del problema di velocity regulation come la stampa, generazione di punti ecc if rule_num == 0: self.solver.add(self.thresholds[0][0][0] >= 0.70) if rule_num == 1: self.solver.add(self.thresholds[1][0][2] >= 0.70) # build soft clauses for run in range(len(self.belief_in_runs)): t = self.thresholds[rule_num] for bel, belief in enumerate(self.belief_in_runs[run]): # generate boolean var for soft constraints soft = z3.Bool('b_{}_{}_{}'.format(rule_num, run, bel)) self.soft_constr[rule_num].append( DummyVar(soft, rule_num, run, bel)) # add the rule subrules = [] for c in range(len(rule.constraints)): subrule = [] for i in rule.constraints[c].greater_equal: subrule.append( belief[i] >= t[c][i] ) #100 > x1 (esempio) ogni belief è preso da uno step, x1 deve essere soddisfatta per tutti gli step for i in rule.constraints[c].lower_equal: subrule.append(belief[i] <= t[c][i]) subrules.append(z3.And(subrule)) formula = z3.Or( subrules) #ho più modi per soddisfare queste regole. #la mia regola deve spiegare se ha fatto l'azione, altrimenti non deve spiegarla. if self.actions_in_runs[run][ bel] not in rule.speeds: #vedo se l'azione scelta viene rispettata dal bielef formula = z3.Not(formula) self.solver.add( z3.Or(soft, formula) ) #può essere risolto dall cheat (soft) oppure dalla formula. # solve MAX-SMT problem low_threshold = 0 total_soft_constr = len(self.soft_constr[rule_num]) high_threshold = len(self.soft_constr[rule_num]) final_threshold = -1 best_model = [] #uso una ricerca binaria per risolvere l'or gigante definito sopra! while low_threshold <= high_threshold: self.solver.push( ) #risolutore incrementale, consente di evitare di rifare calcoli creando un ambiente virtuale threshold = (low_threshold + high_threshold) // 2 #Pble pseudo boolean less equal self.solver.add( z3.PbLe([(soft.literal, 1) for soft in self.soft_constr[rule_num]], threshold) ) #l'add viene fatto sull'ambiente virtuale appena creato. result = self.solver.check() if result == z3.sat: final_threshold = threshold best_model = self.solver.model() high_threshold = threshold - 1 else: low_threshold = threshold + 1 self.solver.pop() print('fail to satisfy {} steps out of {}'.format( final_threshold, total_soft_constr)) # return a model that satisfy all the hard clauses and the maximum number of soft clauses # print(best_model) return best_model
def find_max_satisfiable_rule(self, rule_num): """ Build a model that satisfies as many soft clauses as possible using MAX-SMT """ print('Find maximum number of satisfiable step in rule {}'.format( rule_num)) rule = self.rules[rule_num] # enforce probability axioms for c in range(len(rule.constraints)): # constraint in rule self.thresholds[rule_num].append([None, None, None]) for s in range(3): # state in constraint t = z3.Real('t_r{}_c{}_state{}'.format(rule_num, c, s)) self.thresholds[rule_num][c][s] = t # each threshold is a probability and must have a value # bethween 0 and 1 self.solver.add(0.0 < t) self.solver.add(t <= 1.0) # the sum of the probability on the three states must be 1 prob_sum = z3.Sum(self.thresholds[rule_num][c]) self.solver.add(prob_sum == 1.0) # hard constraint, they must be be specified by hand in this version # e.g: x_1 >= 0.9 self.solver.add(self.thresholds[rule_num][0][0] >= 0.9) # build soft clauses for run in range(len(self.belief_in_runs)): t = self.thresholds[rule_num] for bel, belief in enumerate(self.belief_in_runs[run]): # generate boolean var for soft constraints soft = z3.Bool('b_{}_{}_{}'.format(rule_num, run, bel)) self.soft_constr[rule_num].append( DummyVar(soft, rule_num, run, bel)) # add the rule subrules = [] for c in range(len(rule.constraints)): subrule = [] for i in rule.constraints[c].greater_equal: subrule.append(belief[i] >= t[c][i]) for i in rule.constraints[c].lower_equal: subrule.append(belief[i] <= t[c][i]) subrules.append(z3.And(subrule)) formula = z3.Or(subrules) if self.actions_in_runs[run][bel] in rule.speeds: self.solver.add(z3.Or(soft, formula)) else: self.solver.add(z3.Or(soft, z3.Not(formula))) # solve MAX-SMT problem low_threshold = 0 total_soft_constr = len(self.soft_constr[rule_num]) high_threshold = len(self.soft_constr[rule_num]) final_threshold = -1 best_model = [] while low_threshold <= high_threshold: self.solver.push() threshold = (low_threshold + high_threshold) // 2 self.solver.add( z3.PbLe([(soft.literal, 1) for soft in self.soft_constr[rule_num]], threshold)) result = self.solver.check() if result == z3.sat: final_threshold = threshold best_model = self.solver.model() high_threshold = threshold - 1 else: low_threshold = threshold + 1 self.solver.pop() print('fail to satisfy {} steps out of {}'.format( final_threshold, total_soft_constr)) # return a model that satisfy all the hard clauses and the maximum number of soft clauses return best_model