Esempio n. 1
0
 def integrate(self, domain: Domain, expression: int, variables=None) -> int:
     result = expression
     integrator = ResolveIntegrator(
         self.pool, reduce_strategy=self.reduce_strategy[1],
     )
     for v in variables or domain.variables:
         result = integrator.integrate(result, domain.get_symbol(v))
     return result
Esempio n. 2
0
def bool_xor_problem():
    variables = ["a", "b"]
    var_types = {"a": BOOL, "b": BOOL}
    var_domains = dict()
    domain = Domain(variables, var_types, var_domains)

    a, b = (domain.get_symbol(v) for v in variables)

    theory = (a & ~b) | (~a & b)
    return domain, theory, "2xor"
Esempio n. 3
0
def ice_cream_problem():
    variables = ["chocolate", "banana", "weekend"]
    chocolate, banana, weekend = variables
    var_types = {chocolate: REAL, banana: REAL, weekend: BOOL}
    var_domains = {chocolate: (0, 1), banana: (0, 1)}
    domain = Domain(variables, var_types, var_domains)

    chocolate, banana, weekend = (domain.get_symbol(v) for v in variables)
    theory = (chocolate < 0.650) \
             & (banana < 0.550) \
             & (chocolate + 0.7 * banana <= 0.700) \
             & (chocolate + 1.2 * banana <= 0.750) \
             & (~weekend | (chocolate + 0.7 * banana <= 0.340))

    return domain, theory, "ice_cream"
Esempio n. 4
0
def plot_combined(feat_x: Union[str, int],
                  feat_y: Union[str, int],
                  domain: Domain,
                  formula: Optional[FNode],
                  data: Union[Tuple[np.ndarray, np.ndarray],
                              List[Tuple[Dict, bool]]],
                  learned_labels: Optional[List[bool]],
                  name: str,
                  active_indices: Set[int],
                  new_active_indices: Set[int],
                  condition: Optional[callable] = None):

    row_vars = domain.bool_vars[:int(len(domain.bool_vars) / 2)]
    col_vars = domain.bool_vars[int(len(domain.bool_vars) / 2):]
    sf_size = 2

    fig = plt.figure(num=None,
                     figsize=(2**len(col_vars) * sf_size,
                              2**len(row_vars) * sf_size),
                     dpi=300)

    for assignment in itertools.product([True, False],
                                        repeat=len(domain.bool_vars)):
        row = 0
        for b in assignment[:len(row_vars)]:
            row = row * 2 + (1 if b else 0)

        col = 0
        for b in assignment[len(row_vars):]:
            col = col * 2 + (1 if b else 0)

        index = row * (2**len(col_vars)) + col
        ax = fig.add_subplot(2**len(row_vars), 2**len(col_vars), 1 + index)

        if formula is not None:
            substitution = {
                domain.get_symbol(v): smt.Bool(a)
                for v, a in zip(domain.bool_vars, assignment)
            }
            substituted = smt.simplify(formula.substitute(substitution))
            try:
                region = RegionBuilder(domain).walk_smt(substituted)
                try:
                    if region.dim == 2:
                        region.linestyle = None
                        region.plot(ax=ax, color="green", alpha=0.2)
                except IndexError:
                    pass
            except ValueError:
                pass

        points = []

        def status(_i):
            return "active" if _i in active_indices else (
                "new_active" if _i in new_active_indices else "excluded")

        if isinstance(data, tuple):
            values, labels = data  # type: Tuple[np.ndarray, np.ndarray]
            var_index_map = domain.var_index_map()
            fx, fy = (f if isinstance(f, int) else var_index_map[f]
                      for f in (feat_x, feat_y))
            # noinspection PyUnresolvedReferences
            for i in range(values.shape[0]):
                row = values[i, :]
                point = row[fx], row[fy]
                label = labels[i] == 1
                correct = (learned_labels[i]
                           == label) if learned_labels is not None else True
                match = all(row[var_index_map[v]] == a
                            for v, a in zip(domain.bool_vars, assignment))
                if match and (condition is None or condition(row, label)):
                    points.append((label, correct, status(i), point))
        else:
            for i in range(len(data)):
                instance, label = data[i]
                point = (float(instance[feat_x]), float(instance[feat_y]))
                correct = (learned_labels[i]
                           == label) if learned_labels is not None else True
                match = all(instance[v] == a
                            for v, a in zip(domain.bool_vars, assignment))
                if match and (condition is None or condition(instance, label)):
                    points.append((label, correct, status(i), point))

        def get_color(_l, _c, _s):
            if _s == "active":
                return "black"
            return "green" if _l else "red"

        def get_marker(_l, _c, _s):
            # if _s == "active":
            #     return "v"
            return "+" if _l else "."

        def get_alpha(_l, _c, _s):
            if _s == "active":
                return 0.5
            elif _s == "new_active":
                return 1
            elif _s == "excluded":
                return 0.2

        for label in [True, False]:
            for correct in [True, False]:
                for status in ["active", "new_active", "excluded"]:
                    marker, color, alpha = [
                        f(label, correct, status)
                        for f in (get_marker, get_color, get_alpha)
                    ]
                    selection = [
                        p for l, c, s, p in points
                        if l == label and c == correct and s == status
                    ]
                    if len(selection) > 0:
                        ax.scatter(*zip(*selection),
                                   c=color,
                                   marker=marker,
                                   alpha=alpha)

        ax.set_xlim(domain.var_domains[feat_x])
        ax.set_ylim(domain.var_domains[feat_y])

    if name is not None:
        plt.savefig(name if name.endswith(".png") else "{}.png".format(name))
    else:
        plt.show()
    plt.close(fig)
Esempio n. 5
0
    def learn_partial(self, solver, domain: Domain, data: np.ndarray,
                      labels: np.ndarray, new_active_indices: Set):

        # Constants
        n_b_original = len(domain.bool_vars)
        n_b = n_b_original * 2
        n_r = len(domain.real_vars)

        n_h_original = self.half_space_count if n_r > 0 else 0
        n_h = n_h_original * 2 if self.allow_negations else n_h_original

        n_c = self.conjunction_count
        n_d = data.shape[0]

        real_indices = np.array(
            [domain.var_types[v] == smt.REAL for v in domain.variables])
        real_features = data[:, real_indices]
        bool_features = data[:, np.logical_not(real_indices)]

        # Variables
        a_hr = [[
            smt.Symbol("a_hr[{}][{}]".format(h, r), REAL) for r in range(n_r)
        ] for h in range(n_h_original)]
        b_h = [
            smt.Symbol("b_h[{}]".format(h), REAL) for h in range(n_h_original)
        ]
        s_ch = [[smt.Symbol("s_ch[{}][{}]".format(c, h)) for h in range(n_h)]
                for c in range(n_c)]
        s_cb = [[smt.Symbol("s_cb[{}][{}]".format(c, b)) for b in range(n_b)]
                for c in range(n_c)]

        # Aux variables
        s_ih = [[smt.Symbol("s_ih[{}][{}]".format(i, h)) for h in range(n_h)]
                for i in range(n_d)]
        s_ic = [[smt.Symbol("s_ic[{}][{}]".format(i, c)) for c in range(n_c)]
                for i in range(n_d)]

        def pair(real: bool, c: int, index: int) -> Tuple[FNode, FNode]:
            if real:
                return s_ch[c][index], s_ch[c][index + n_h_original]
            else:
                return s_cb[c][index], s_cb[c][index + n_b_original]

        def order_equal(pair1, pair2):
            x_t, x_f, y_t, y_f = pair1 + pair2
            return smt.Iff(x_t, y_t) & smt.Iff(x_f, y_f)

        def order_geq(pair1, pair2):
            x_t, x_f, y_t, y_f = pair1 + pair2
            return x_t | y_f | ((~x_f) & (~y_t))

        def pairs(c: int) -> List[Tuple[FNode, FNode]]:
            return [pair(True, c, i) for i in range(n_h_original)
                    ] + [pair(False, c, i) for i in range(n_b_original)]

        def order_geq_lex(c1: int, c2: int):
            pairs_c1, pairs_c2 = pairs(c1), pairs(c2)
            assert len(pairs_c1) == len(pairs_c2)
            constraints = smt.TRUE()
            for j in range(len(pairs_c1)):
                condition = smt.TRUE()
                for i in range(j):
                    condition &= order_equal(pairs_c1[i], pairs_c2[i])
                constraints &= smt.Implies(condition,
                                           order_geq(pairs_c1[j], pairs_c2[j]))
            return constraints

        # Constraints
        for i in new_active_indices:
            x_r, x_b, label = [float(val) for val in real_features[i]
                               ], bool_features[i], labels[i]

            for h in range(n_h_original):
                sum_coefficients = smt.Plus(
                    [a_hr[h][r] * smt.Real(x_r[r]) for r in range(n_r)])
                solver.add_assertion(
                    smt.Iff(s_ih[i][h], sum_coefficients <= b_h[h]))

            for h in range(n_h_original, n_h):
                solver.add_assertion(
                    smt.Iff(s_ih[i][h], ~s_ih[i][h - n_h_original]))

            for c in range(n_c):
                solver.add_assertion(
                    smt.Iff(
                        s_ic[i][c],
                        smt.
                        Or([smt.FALSE()] + [(s_ch[c][h] & s_ih[i][h])
                                            for h in range(n_h)] +
                           [s_cb[c][b]
                            for b in range(n_b_original) if x_b[b]] + [
                                s_cb[c][b] for b in range(n_b_original, n_b)
                                if not x_b[b - n_b_original]
                            ])))

            # --- [start] symmetry breaking ---
            # Mutually exclusive
            if "m" in self.symmetries:
                for c in range(n_c):
                    for h in range(n_h_original):
                        solver.add_assertion(~(s_ch[c][h]
                                               & s_ch[c][h + n_h_original]))
                    for b in range(n_b_original):
                        solver.add_assertion(~(s_cb[c][b]
                                               & s_cb[c][b + n_b_original]))

            # Normalized
            if "n" in self.symmetries:
                for h in range(n_h_original):
                    solver.add_assertion(
                        smt.Equals(b_h[h], smt.Real(1.0))
                        | smt.Equals(b_h[h], smt.Real(0.0)))

            # Vertical symmetries
            if "v" in self.symmetries:
                for c in range(n_c - 1):
                    solver.add_assertion(order_geq_lex(c, c + 1))

            # Horizontal symmetries
            if "h" in self.symmetries:
                for h in range(n_h_original - 1):
                    solver.add_assertion(a_hr[h][0] >= a_hr[h + 1][0])
            # --- [end] symmetry breaking ---

            if label:
                solver.add_assertion(smt.And([s_ic[i][c] for c in range(n_c)]))
            else:
                solver.add_assertion(smt.Or([~s_ic[i][c] for c in range(n_c)]))

        solver.solve()
        model = solver.get_model()

        x_vars = [domain.get_symbol(domain.real_vars[r]) for r in range(n_r)]
        half_spaces = [
            smt.Plus(
                [model.get_value(a_hr[h][r]) * x_vars[r]
                 for r in range(n_r)]) <= model.get_value(b_h[h])
            for h in range(n_h_original)
        ] + [
            smt.Plus(
                [model.get_value(a_hr[h][r]) * x_vars[r]
                 for r in range(n_r)]) > model.get_value(b_h[h])
            for h in range(n_h - n_h_original)
        ]

        b_vars = [
            domain.get_symbol(domain.bool_vars[b]) for b in range(n_b_original)
        ]
        bool_literals = [b_vars[b] for b in range(n_b_original)]
        bool_literals += [~b_vars[b] for b in range(n_b - n_b_original)]

        conjunctions = [[
            half_spaces[h]
            for h in range(n_h) if model.get_py_value(s_ch[c][h])
        ] + [
            bool_literals[b]
            for b in range(n_b) if model.get_py_value(s_cb[c][b])
        ] for c in range(n_c)]

        return smt.And([smt.Or(conjunction) for conjunction in conjunctions])