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
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"
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"
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)
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])