def __init__(self, value=SMYBOLIC, *, name=AUTOMATIC, prefix=AUTOMATIC): if (name is not AUTOMATIC or prefix is not AUTOMATIC) and value is not SMYBOLIC: raise TypeError('Can only name symbolic variables') elif name is not AUTOMATIC and prefix is not AUTOMATIC: raise ValueError('Can only set either name or prefix not both') elif name is not AUTOMATIC: if not isinstance(name, str): raise TypeError('Name must be string') elif name in _name_table: raise ValueError(f'Name {name} already in use') elif _name_re.fullmatch(name): warnings.warn( 'Name looks like an auto generated name, this might break things' ) _name_table[name] = self elif prefix is not AUTOMATIC: name = _gen_name(prefix) _name_table[name] = self elif name is AUTOMATIC and value is SMYBOLIC: name = _gen_name() _name_table[name] = self if value is SMYBOLIC: self._value = smt.Symbol(name, BOOL) elif isinstance(value, pysmt.fnode.FNode): if value.get_type().is_bool_type(): self._value = value else: raise TypeError(f'Expected bool type not {value.get_type()}') elif isinstance(value, SMTBit): if name is not AUTOMATIC and name != value.name: warnings.warn( 'Changing the name of a SMTBit does not cause a new underlying smt variable to be created' ) self._value = value._value elif isinstance(value, bool): self._value = smt.Bool(value) elif isinstance(value, int): if value not in {0, 1}: raise ValueError( 'Bit must have value 0 or 1 not {}'.format(value)) self._value = smt.Bool(bool(value)) elif hasattr(value, '__bool__'): self._value = smt.Bool(bool(value)) else: raise TypeError("Can't coerce {} to Bit".format(type(value))) self._name = name self._value = smt.simplify(self._value)
def walk_constant(self, value, v_type): if v_type == smt.BOOL: return smt.Bool(value) elif v_type == smt.REAL: return smt.Real(value) else: return ValueError("Unknown type {}".format(v_type))
def sympy2pysmt(expr, expr_type=None): if type(expr ) == Poly: # turn Poly instances into generic sympy expressions expr = expr.as_expr() op = type(expr) if len(expr.free_symbols) == 0: if expr.is_Boolean: return smt.Bool(bool(expr)) elif expr.is_number: return smt.Real(float(expr)) elif op == sym.Symbol: if expr_type is None: raise ValueError( "Can't create a pysmt Symbol without type information") return smt.Symbol(expr.name, expr_type) elif op in SYM2SMT: if expr_type is None: expr_type = OP_TYPE[op] smtargs = [sympy2pysmt(c, expr_type) for c in expr.args] return SYM2SMT[op](*smtargs) raise NotImplementedError(f"SYMPY -> PYSMT Not implemented for op: {op}")
def test_simpleSymbol_false(self): symbol_name = "b" checker = SmtChecker({symbol_name: False}) self.assertFalse(checker.walk_smt(smt.Symbol(symbol_name))) checker = SmtChecker({symbol_name: smt.Bool(False)}) self.assertFalse(checker.walk_smt(smt.Symbol(symbol_name)))
def test_simpleSymbol_true(self): symbol_name = "b" checker = SmtChecker({symbol_name: True}) self.assertTrue(checker.walk_smt(smt.Symbol(symbol_name))) checker = SmtChecker({symbol_name: smt.Bool(True)}) self.assertTrue(checker.walk_smt(smt.Symbol(symbol_name)))
def ast_to_smt(self, node): """ :type node: Node """ def convert_children(number=None): if number is not None and len(node.children) != number: raise Exception( "The number of children ({}) differed from {}".format( len(node.children), number)) return [self.ast_to_smt(child) for child in node.children] if node.name == "ite": return smt.Ite(*convert_children(3)) elif node.name == "~": return smt.Not(*convert_children(1)) elif node.name == "^": return smt.Pow(*convert_children(2)) elif node.name == "&": return smt.And(*convert_children()) elif node.name == "|": return smt.Or(*convert_children()) elif node.name == "*": return smt.Times(*convert_children()) elif node.name == "+": return smt.Plus(*convert_children()) elif node.name == "-": return smt.Minus(*convert_children(2)) elif node.name == "<=": return smt.LE(*convert_children(2)) elif node.name == ">=": return smt.GE(*convert_children(2)) elif node.name == "<": return smt.LT(*convert_children(2)) elif node.name == ">": return smt.GT(*convert_children(2)) elif node.name == "=": return smt.Equals(*convert_children(2)) elif node.name == "const": c_type, c_value = [child.name for child in node.children] if c_type == "bool": return smt.Bool(bool(c_value)) elif c_type == "real": return smt.Real(float(c_value)) else: raise Exception("Unknown constant type {}".format(c_type)) elif node.name == "var": v_type, v_name = [child.name for child in node.children] if v_type == "bool": v_smt_type = smt.BOOL elif v_type == "real": v_smt_type = smt.REAL else: raise Exception("Unknown variable type {}".format(v_type)) return smt.Symbol(v_name, v_smt_type) else: raise RuntimeError("Unrecognized node type '{}'".format(node.name))
def test_pysmt_operations(self, width, x, y): try: from pysmt import shortcuts as sc except ImportError: return modulus = 2 ** width x = x % modulus y = y % modulus bvx = Constant(x, width) bvy = Constant(y, width) psx = sc.BV(x, width) psy = sc.BV(y, width) def eval_pysmt(pysmt_var): return pysmt_var.simplify().constant_value() self.assertEqual(~bvx, eval_pysmt(sc.BVNot(psx))) self.assertEqual(bvx & bvy, eval_pysmt(sc.BVAnd(psx, psy))) self.assertEqual(bvx | bvy, eval_pysmt(sc.BVOr(psx, psy))) self.assertEqual(bvx ^ bvy, eval_pysmt(sc.BVXor(psx, psy))) self.assertEqual(BvComp(bvx, bvy), eval_pysmt(sc.BVComp(psx, psy))) self.assertEqual((bvx < bvy), eval_pysmt(sc.BVULT(psx, psy))) self.assertEqual((bvx <= bvy), eval_pysmt(sc.BVULE(psx, psy))) self.assertEqual((bvx > bvy), eval_pysmt(sc.BVUGT(psx, psy))) self.assertEqual((bvx >= bvy), eval_pysmt(sc.BVUGE(psx, psy))) r = y % bvx.width self.assertEqual(bvx << bvy, eval_pysmt(sc.BVLShl(psx, psy))) self.assertEqual(bvx >> bvy, eval_pysmt(sc.BVLShr(psx, psy))) self.assertEqual(RotateLeft(bvx, r), eval_pysmt(sc.BVRol(psx, r))) self.assertEqual(RotateRight(bvx, r), eval_pysmt(sc.BVRor(psx, r))) bvb = Constant(y % 2, 1) psb = sc.Bool(bool(bvb)) self.assertEqual(Ite(bvb, bvx, bvy), eval_pysmt(sc.Ite(psb, psx, psy))) j = y % bvx.width self.assertEqual(bvx[:j], eval_pysmt(sc.BVExtract(psx, start=j))) self.assertEqual(bvx[j:], eval_pysmt(sc.BVExtract(psx, end=j))) self.assertEqual(Concat(bvx, bvy), eval_pysmt(sc.BVConcat(psx, psy))) self.assertEqual(ZeroExtend(bvx, j), eval_pysmt(sc.BVZExt(psx, j))) self.assertEqual(Repeat(bvx, 1 + j), eval_pysmt(psx.BVRepeat(1 + j))) self.assertEqual(-bvx, eval_pysmt(sc.BVNeg(psx))) self.assertEqual(bvx + bvy, eval_pysmt(sc.BVAdd(psx, psy))) self.assertEqual(bvx - bvy, eval_pysmt(sc.BVSub(psx, psy))) self.assertEqual(bvx * bvy, eval_pysmt(sc.BVMul(psx, psy))) if bvy > 0: self.assertEqual(bvx / bvy, eval_pysmt(sc.BVUDiv(psx, psy))) self.assertEqual(bvx % bvy, eval_pysmt(sc.BVURem(psx, psy)))
def __encodeTerminal(symbolicExpression, type): if isinstance(symbolicExpression, sympy.Symbol): if type.literal == 'Integer': return pysmt.Symbol(symbolicExpression.name, pysmt.INT) elif type.literal == 'Real': return pysmt.Symbol(symbolicExpression.name, pysmt.REAL) elif type.literal == 'Bool': return pysmt.Symbol(symbolicExpression.name, pysmt.BOOL) else: # type.literal == 'BitVector' return pysmt.Symbol(symbolicExpression.name, pysmt.BVType(type.size)) else: if type.literal == 'Integer': return pysmt.Int(symbolicExpression.p) elif type.literal == 'Real': if isinstance(symbolicExpression, sympy.Rational): return pysmt.Real(symbolicExpression.p / symbolicExpression.q) else: # isinstance(symbolicExpression, sympy.Float) return pysmt.Real(symbolicExpression) elif type.literal == 'Bool': return pysmt.Bool(symbolicExpression) else: # type.literal == 'BitVector' return pysmt.BV(symbolicExpression, type.size)
def draw_points(feat_x, feat_y, domain, formula, data, learned_labels, name, active_indices, new_active_indices, condition=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 = formula.substitute(substitution) region = RegionBuilder(domain).walk_smt(substituted) try: if region.dim == 2: region.plot(ax=ax, color="green", alpha=0.2) except IndexError: pass points = [] 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 status = "active" if i in active_indices else ("new_active" if i in new_active_indices else "excluded") 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, 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([0, 1]) ax.set_ylim([0, 1]) plt.savefig("{}.png".format(name)) plt.close(fig)
def test_constant_boolean(): formula = smt.Bool(True) result = make_coefficients_positive(formula) assert formula == result
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 test_constant_true(self): checker = SmtChecker({}) self.assertTrue(checker.walk_smt(smt.Bool(True)))
def test_constant_false(self): checker = SmtChecker({}) self.assertFalse(checker.walk_smt(smt.Bool(False)))