def test_get_strict_formula(self): smtlib_single = """ (set-logic UF_LIRA) (declare-fun x () Bool) (declare-fun y () Bool) (declare-fun r () Real) (assert (> r 0.0)) (assert x) (check-sat) """ smtlib_double = smtlib_single + """ (assert (not y)) (check-sat) """ r = Symbol("r", REAL) x, y = Symbol("x"), Symbol("y") target_one = And(GT(r, Real(0)), x) target_two = And(GT(r, Real(0)), x, Not(y)) stream_in = cStringIO(smtlib_single) f = get_formula(stream_in) self.assertEqual(f, target_one) stream_in = cStringIO(smtlib_double) f = get_formula(stream_in) self.assertEqual(f, target_two) stream_in = cStringIO(smtlib_double) with self.assertRaises(PysmtValueError): f = get_formula_strict(stream_in)
def simple_checker_problem(): theory = Or( And(LE(Symbol("x", REAL), Real(0.5)), LE(Symbol("y", REAL), Real(0.5))), And(GT(Symbol("x", REAL), Real(0.5)), GT(Symbol("y", REAL), Real(0.5))) ) return xy_domain(), theory, "simple_checker"
def test_str_substr(self): s1 = Symbol("s1", STRING) i = Symbol("index", INT) f = And( GT(i, Int(0)), GT(StrLength(s1), Int(1)), LT(i, StrLength(s1)), Equals( StrConcat(StrSubstr(s1, Int(0), i), StrSubstr(s1, Plus(i, Int(1)), StrLength(s1))), s1)) self.assertUnsat(f)
def test_substitution_term(self): x, y = FreshSymbol(REAL), FreshSymbol(REAL) # y = 0 /\ Forall x. x > 3 f = And(Equals(y, Real(0)), ForAll([x], GT(x, Real(3)))) subs = {GT(x, Real(3)): TRUE()} f_subs = substitute(f, subs) # Since 'x' is quantified, we cannot replace the term # therefore the substitution does not yield any result. self.assertEqual(f_subs, f)
def test_substitution_complex_mss(self): x, y = FreshSymbol(REAL), FreshSymbol(REAL) # y = 0 /\ (Forall x. x > 3 /\ y < 2) f = And(Equals(y, Real(0)), ForAll([x], And(GT(x, Real(3)), LT(y, Real(2))))) subs = { y: Real(0), ForAll([x], And(GT(x, Real(3)), LT(Real(0), Real(2)))): TRUE() } f_subs = MSSubstituter(env=self.env).substitute(f, subs).simplify() self.assertEqual(f_subs, TRUE())
def main(): x,y = [Symbol(n, REAL) for n in "xy"] f_sat = Implies(And(GT(y, Real(0)), LT(y, Real(10))), LT(Minus(y, Times(x, Real(2))), Real(7))) f_incomplete = And(GT(x, Real(0)), LE(x, Real(10)), Implies(And(GT(y, Real(0)), LE(y, Real(10)), Not(Equals(x, y))), GT(y, x))) run_test([y], f_sat) run_test([y], f_incomplete)
def checker_problem(): variables = ["x", "y", "a"] var_types = {"x": REAL, "y": REAL, "a": BOOL} var_domains = {"x": (0, 1), "y": (0, 1)} theory = Or( And(LE(Symbol("x", REAL), Real(0.5)), LE(Symbol("y", REAL), Real(0.5)), Symbol("a", BOOL)), And(GT(Symbol("x", REAL), Real(0.5)), GT(Symbol("y", REAL), Real(0.5)), Symbol("a", BOOL)), And(GT(Symbol("x", REAL), Real(0.5)), LE(Symbol("y", REAL), Real(0.5)), Not(Symbol("a", BOOL))), And(LE(Symbol("x", REAL), Real(0.5)), GT(Symbol("y", REAL), Real(0.5)), Not(Symbol("a", BOOL))) ) return Domain(variables, var_types, var_domains), theory, "checker"
def test_lira(self): varA = Symbol("A", REAL) varB = Symbol("B", INT) with self.assertRaises(PysmtTypeError): f = And(LT(varA, Plus(varA, Real(1))), GT(varA, Minus(varB, Int(1)))) f = And(LT(varA, Plus(varA, Real(1))), GT(varA, ToReal(Minus(varB, Int(1))))) g = Equals(varA, ToReal(varB)) self.assertUnsat(And(f, g, Equals(varA, Real(1.2))), "Formula was expected to be unsat", logic=QF_UFLIRA)
def test_named_unsat_core_with_assumptions(self): i0 = Int(0) a = GT(Symbol("a", INT), i0) b = GT(Symbol("b", INT), i0) c = GT(Symbol("c", INT), i0) n_a = Not(a) n_b = Not(b) n_c = Not(c) formulae = [Or(b, n_a), Or(c, n_a), Or(n_a, n_b, n_c)] with UnsatCoreSolver(logic=QF_LIA, unsat_cores_mode="named") as solver: for i, f in enumerate(formulae): solver.add_assertion(f, named=f"f{i}") sat = solver.solve([a]) self.assertFalse(sat)
def test_get_value_of_function_bool(self): """Proper handling of models with functions with bool args.""" hr = Symbol("hr", FunctionType(REAL, [BOOL, REAL, REAL])) hb = Symbol("hb", FunctionType(BOOL, [BOOL, REAL, REAL])) hr_0_1 = Function(hr, (TRUE(), Real(0), Real(1))) hb_0_1 = Function(hb, (TRUE(), Real(0), Real(1))) hbx = Function(hb, (Symbol("x"), Real(0), Real(1))) f = GT(hr_0_1, Real(0)) g = hb_0_1 for sname in get_env().factory.all_solvers(logic=QF_UFLIRA): with Solver(name=sname) as solver: # First hr solver.add_assertion(f) res = solver.solve() self.assertTrue(res) v = solver.get_value(hr_0_1) self.assertIsNotNone(solver.get_value(v)) # Now hb solver.add_assertion(g) res = solver.solve() self.assertTrue(res) v = solver.get_value(hb_0_1) self.assertIsNotNone(v in [TRUE(), FALSE()]) # Hbx solver.add_assertion(hbx) res = solver.solve() self.assertTrue(res) v = solver.get_value(hbx) self.assertIsNotNone(v in [TRUE(), FALSE()]) # Get model model = solver.get_model() self.assertIsNotNone(model)
def test_ints(self): f = And(LT(Symbol("x", INT), Int(2)), GT(Symbol("x", INT), Int(2))) for n in self.all_solvers: with Solver(name=n, logic=QF_UFLIA) as s: s.add_assertion(f) res = s.solve() self.assertFalse(res)
def test_solving_under_assumption_theory(self): x = Symbol("x", REAL) y = Symbol("y", REAL) v1 = GT(x, Real(10)) v2 = LE(y, Real(2)) xor = Or(And(v1, Not(v2)), And(Not(v1), v2)) for name in get_env().factory.all_solvers(logic=QF_LRA): with Solver(name=name) as solver: solver.add_assertion(xor) res1 = solver.solve(assumptions=[v1, Not(v2)]) model1 = solver.get_model() res2 = solver.solve(assumptions=[Not(v1), v2]) model2 = solver.get_model() res3 = solver.solve(assumptions=[v1, v2]) self.assertTrue(res1) self.assertTrue(res2) self.assertFalse(res3) self.assertEqual(model1.get_value(v1), TRUE()) self.assertEqual(model1.get_value(v2), FALSE()) self.assertEqual(model2.get_value(v1), FALSE()) self.assertEqual(model2.get_value(v2), TRUE())
def _op_raw_gt(self, *args): # We emulate the integer through a bitvector but # since a constraint with the form (assert (= (str.len Symb_str) bit_vect)) # is not valid we need to tranform the concrete vqalue of the bitvector in an integer # # TODO: implement logic for integer return GT(*_normalize_arguments(*args))
def test_msat_converter_on_msat_error(self): import mathsat import _mathsat from pysmt.solvers.msat import MathSAT5Solver, MSatConverter env = get_env() msat = MathSAT5Solver(env, logic=QF_UFLIRA) new_converter = MSatConverter(env, msat.msat_env) def walk_plus(formula, args): res = mathsat.MSAT_MAKE_ERROR_TERM() return res # Replace the function used to compute the Plus() # with one that returns a msat_error new_converter.set_function(walk_plus, op.PLUS) r, s = FreshSymbol(REAL), FreshSymbol(REAL) f1 = GT(r, s) f2 = Plus(r, s) t1 = new_converter.convert(f1) self.assertFalse(mathsat.MSAT_ERROR_TERM(t1)) with self.assertRaises(InternalSolverError): new_converter.convert(f2)
def add_relu_eager_constraint(self): # Eager lemma encoding for relus zero = Real(0) for r, relu_in in self.relus: self.formulae.append(Implies(GT(relu_in, zero), Equals(r, relu_in))) self.formulae.append(Implies(LE(relu_in, zero), Equals(r, zero)))
def test_energy_ranges(self): """Check that the energy ranges were set the way we expect""" linear_ranges = defaultdict(lambda: (-2., 2.)) quadratic_ranges = defaultdict(lambda: (-1., 1.)) for graph in self.graphs: theta = Theta.from_graph(graph, linear_ranges, quadratic_ranges) for v, bias in theta.linear.items(): min_, max_ = linear_ranges[v] self.assertUnsat(And(GT(bias, limitReal(max_)), And(theta.assertions))) self.assertUnsat(And(LT(bias, limitReal(min_)), And(theta.assertions))) for (u, v), bias in theta.quadratic.items(): min_, max_ = quadratic_ranges[(u, v)] self.assertUnsat(And(GT(bias, limitReal(max_)), And(theta.assertions))) self.assertUnsat(And(LT(bias, limitReal(min_)), And(theta.assertions)))
def test_msat_back_not_identical(self): msat = Solver(name="msat", logic=QF_UFLIRA) r, s = FreshSymbol(REAL), FreshSymbol(REAL) # r + 1 > s + 1 f = GT(Plus(r, Real(1)), Plus(s, Real(1))) term = msat.converter.convert(f) res = msat.converter.back(term) self.assertFalse(f == res)
def add_relu_simplex_friendly_eager(self): # Eager lemma encoding for relus zero = Real(0) for relu_out, relu_in in self.relus: #Introduce f = relu_out - relu_in f = FreshSymbol(REAL) self.formulae.append(Equals(f, Minus(relu_out, relu_in))) self.formulae.append(Implies(GT(relu_in, zero), Equals(f, zero))) self.formulae.append( Implies(LE(relu_in, zero), Equals(relu_out, zero)))
def test_theory_oracle(self): from pysmt.oracles import get_logic s1 = Symbol("s1", STRING) s2 = Symbol("s2", STRING) f = Equals(StrConcat(s1, s1), s2) theory = get_logic(f).theory self.assertTrue(theory.strings, theory) f = Not( And(GE(StrLength(StrConcat(s1, s2)), StrLength(s1)), GE(StrLength(StrConcat(s1, s2)), StrLength(s2)))) theory = get_logic(f).theory self.assertTrue(theory.strings, theory) f = And(GT(StrLength(s1), Int(2)), GT(StrLength(s2), StrLength(s1)), And(StrSuffixOf(s2, s1), StrContains(s2, s1))) theory = get_logic(f).theory self.assertTrue(theory.strings, theory)
def test_str_replace(self): s1 = Symbol("s1", STRING) s2 = Symbol("s2", STRING) s3 = Symbol("s3", STRING) f = Equals(StrReplace(s1, s2, s3), s3) self.assertSat(f) f = And(GT(StrLength(s1), Int(0)), GT(StrLength(s2), Int(0)), GT(StrLength(s3), Int(0)), Not(StrContains(s1, s2)), Not(StrContains(s1, s3)), Not(Equals(StrReplace(StrReplace(s1, s2, s3), s3, s2), s1))) self.assertUnsat(f) # Replace first v Replace First f = Implies( And(Equals(s1, String("Hello")), Equals(s2, StrReplace(s1, String("l"), String(" ")))), Equals(s2, String("He lo"))) self.assertValid(f, logic="QF_SLIA")
def test_substitution_complex(self): x, y = Symbol("x", REAL), Symbol("y", REAL) # y = 0 /\ (Forall x. x > 3 /\ y < 2) f = And(Equals(y, Real(0)), ForAll([x], And(GT(x, Real(3)), LT(y, Real(2))))) subs = { y: Real(0), ForAll([x], And(GT(x, Real(3)), LT(y, Real(2)))): TRUE() } f_subs = substitute(f, subs).simplify() if self.env.SubstituterClass == MGSubstituter: self.assertEqual(f_subs, TRUE()) else: # In the MSS the y=0 substitution is performed first, # therefore, the overall quantified expression does not # match the one defined in the substitution map. # See test_substitution_complex_mss for a positive example. self.assertEqual(f_subs, ForAll([x], GT(x, Real(3))))
def test_eq(self): varA = Symbol("At", INT) varB = Symbol("Bt", INT) f = And(LT(varA, Plus(varB, Int(1))), GT(varA, Minus(varB, Int(1)))) g = Equals(varA, varB) self.assertValid(Iff(f, g), "Formulae were expected to be equivalent", logic=QF_LIA)
def test_infix(self): x, y, p = self.x, self.y, self.p with self.assertRaises(Exception): x.Implies(y) get_env().enable_infix_notation = True self.assertEqual(Implies(x, y), x.Implies(y)) self.assertEqual(p + p, Plus(p, p)) self.assertEqual(p > p, GT(p, p))
def test_add_assertion(self): r = FreshSymbol(REAL) f1 = Plus(r, r) f2 = GT(r, r) for sname in get_env().factory.all_solvers(logic=QF_LRA): with Solver(name=sname) as solver: with self.assertRaises(PysmtTypeError): solver.add_assertion(f1) self.assertIsNone(solver.add_assertion(f2))
def test_substitution_complex(self): x, y = FreshSymbol(REAL), FreshSymbol(REAL) # y = 0 /\ (Forall x. x > 3 /\ y < 2) f = And(Equals(y, Real(0)), ForAll([x], And(GT(x, Real(3)), LT(y, Real(2))))) if "MSS" in str(self.env.SubstituterClass): subs = { y: Real(0), ForAll([x], And(GT(x, Real(3)), LT(Real(0), Real(2)))): TRUE() } else: assert "MGS" in str(self.env.SubstituterClass) subs = { y: Real(0), ForAll([x], And(GT(x, Real(3)), LT(y, Real(2)))): TRUE() } f_subs = substitute(f, subs).simplify() self.assertEqual(f_subs, TRUE())
def __init__(self, graph, decision_variables, linear_energy_ranges, quadratic_energy_ranges): self.theta = theta = Theta.from_graph(graph, linear_energy_ranges, quadratic_energy_ranges) self._trees, self._ancestors = _elimination_trees(theta, decision_variables) self.assertions = assertions = theta.assertions self._auxvar_counter = itertools.count() # let's us make fresh aux variables self.gap = gap = Symbol('gap', REAL) assertions.add(GT(gap, Real(0)))
def test_boolean(self): varA = Symbol("At", INT) varB = Symbol("Bt", INT) f = And(LT(varA, Plus(varB, Int(1))), GT(varA, Minus(varB, Int(1)))) g = Equals(varA, varB) h = Iff(f, g) tc = get_env().stc res = tc.walk(h) self.assertEqual(res, BOOL)
def add_relu_maxOA_constraint(self): zero = Real(0) for relu_out, relu_in in self.relus: # MAX abstraction self.formulae.append(GE(relu_out, relu_in)) self.formulae.append(GE(relu_out, zero)) # MAX - case based upper bound self.formulae.append( Implies(GT(relu_in, zero), LE(relu_out, relu_in))) self.formulae.append(Implies(LE(relu_in, zero), LE(relu_out, zero)))
def k_sequence_WH_worst_case(m, K, K_seq_len=100, count=100): k_seq = [Symbol('x_%i' % i, INT) for i in range(K_seq_len)] domain = And([Or(Equals(x, Int(0)), Equals(x, Int(1))) for x in k_seq]) K_window = And([ LE(Plus(k_seq[t:min(K_seq_len, t + K)]), Int(m)) for t in range(max(1, K_seq_len - K + 1)) ]) violate_up = And([ GT(Plus(k_seq[t:min(K_seq_len, t + K)]), Int(m - 1)) for t in range(max(1, K_seq_len - K + 1)) ]) def violate_right_generator(n): return And([ GT(Plus(k_seq[t:min(K_seq_len, t + K + n)]), Int(m)) for t in range(max(1, K_seq_len - (K + n) + 1)) ]) right_shift = 1 formula = And(domain, K_window, violate_up, violate_right_generator(right_shift)) solver = Solver(name='z3', incremental=True, random_seed=randint(2 << 30)) solver.add_assertion(formula) solver.z3.set('timeout', 5 * 60 * 1000) solutions = And() for _ in range(count): while right_shift + K < K_seq_len: try: result = solver.solve() except BaseException: result = None if not result: solver = Solver(name='z3', incremental=True, random_seed=randint(2 << 30)) right_shift += 1 solver.z3.set('timeout', 5 * 60 * 1000) solver.add_assertion( And(solutions, domain, K_window, violate_up, violate_right_generator(right_shift))) else: break try: model = solver.get_model() except BaseException: break model = array(list(map(lambda x: model.get_py_value(x), k_seq)), dtype=bool) yield model solution = Or( [NotEquals(k_seq[i], Int(model[i])) for i in range(K_seq_len)]) solutions = And(solutions, solution) solver.add_assertion(solution)
def add_relu_simplex_friendly_OA(self): zero = Real(0) for relu_out, relu_in in self.relus: #Introduce f = relu_out - relu_in f = FreshSymbol(REAL) self.formulae.append(Equals(f, Minus(relu_out, relu_in))) # MAX abstraction self.formulae.append(GE(f, zero)) self.formulae.append(GE(relu_out, zero)) # MAX - case based upper bound self.formulae.append(Implies(GT(relu_in, zero), LE(f, zero))) self.formulae.append(Implies(LE(relu_in, zero), LE(relu_out, zero)))