Пример #1
0
 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
Пример #2
0
    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
Пример #3
0
    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)))
Пример #4
0
    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)))
Пример #5
0
    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
Пример #7
0
 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))
Пример #8
0
    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)
Пример #9
0
 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))
Пример #11
0
 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)
Пример #12
0
    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
Пример #13
0
    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