Esempio n. 1
0
    def test_substitute_memoization(self):
        a = Symbol("A", BOOL)
        b = Symbol("B", BOOL)

        f = And(a, b)
        g = f.substitute({a:Bool(True)})
        h = f.substitute({a:Bool(False)})

        self.assertNotEqual(h, g)
Esempio n. 2
0
    def test_threshold_printing(self):
        x = Symbol("x")
        f = And(x,x)
        for _ in xrange(10):
            f = And(f,f)

        short_f_str = str(f)
        long_f_str = f.serialize()
        self.assertTrue(len(short_f_str) < len(long_f_str))
Esempio n. 3
0
    def test_get_implicant_unsat(self):
        varA = Symbol("A", BOOL)
        varB = Symbol("B", BOOL)

        f = And(varA, Not(varB))
        g = f.substitute({varB:varA})

        for solver in get_env().factory.all_solvers(logic=QF_BOOL):
            res = get_implicant(g, solver_name=solver)
            self.assertIsNone(res, "Formula was expected to be UNSAT")
Esempio n. 4
0
    def test_is_sat(self):
        varA = Symbol("A", BOOL)
        varB = Symbol("B", BOOL)

        f = And(varA, Not(varB))
        g = f.substitute({varB:varA})

        self.assertUnsat(g, logic=QF_BOOL,
                         msg="Formula was expected to be UNSAT")

        for solver in get_env().factory.all_solvers():
            self.assertUnsat(g, solver_name=solver,
                             msg="Formula was expected to be UNSAT")
Esempio n. 5
0
    def test_create_and_solve(self):
        solver = Solver(logic=QF_BOOL)

        varA = Symbol("A", BOOL)
        varB = Symbol("B", BOOL)

        f = And(varA, Not(varB))

        g = f.substitute({varB:varA})
        solver.add_assertion(g)
        res = solver.solve()
        self.assertFalse(res, "Formula was expected to be UNSAT")

        h = And(g, Bool(False))
        simp_h = h.simplify()
        self.assertEqual(simp_h, Bool(False))
Esempio n. 6
0
    def get_unrolling(self, k):
        """Unrolling of the transition relation from 0 to k:

        E.g. T(0,1) & T(1,2) & ... & T(k-1,k)
        """
        res = []
        for i in range(k + 1):
            subs_i = self.get_subs(i)
            res.append(self.system.trans.substitute(subs_i))
        return And(res)
Esempio n. 7
0
    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))))
Esempio n. 8
0
    def test_boolean(self):
        x, y, z = Symbol("x"), Symbol("y"), Symbol("z")
        f = Or(And(Not(x), Iff(x, y)), Implies(x, z))

        self.assertEqual(f.to_smtlib(daggify=False),
                         "(or (and (not x) (= x y)) (=> x z))")
        self.assertEqual(
            f.to_smtlib(daggify=True),
            "(let ((.def_0 (=> x z))) (let ((.def_1 (= x y))) (let ((.def_2 (not x))) (let ((.def_3 (and .def_2 .def_1))) (let ((.def_4 (or .def_3 .def_0))) .def_4)))))"
        )
Esempio n. 9
0
 def test_stack_recursion(self):
     import sys
     limit = sys.getrecursionlimit()
     f = FreshSymbol()
     p = FreshSymbol()
     for _ in range(limit):
         f = Or(p, And(f, p))
     self.assertTrue(f.size() >= limit)
     s = f.serialize()
     self.assertIsNotNone(s)
Esempio n. 10
0
 def test_warp_solvermodel(self):
     x, y, z = [FreshSymbol() for _ in range(3)]
     with Solver(name='z3') as solver:
         solver.add_assertion(And(x, y, z))
         solver.solve()
         z3_model = solver.get_model()
         eager_model = EagerModel(z3_model)
         for var, value in eager_model:
             self.assertIn(var, [x, y, z])
             self.assertEqual(value, TRUE())
Esempio n. 11
0
    def test_default_logic_in_is_sat(self):
        factory = get_env().factory
        factory.default_logic = QF_BOOL

        self.assertEqual(factory.default_logic, QF_BOOL)
        varA = Symbol("A", BOOL)
        varB = Symbol("B", BOOL)

        f = And(varA, Not(varB))
        self.assertSat(f)
Esempio n. 12
0
    def test_get_implicant_sat(self):
        varA = Symbol("A", BOOL)
        varX = Symbol("X", REAL)

        f = And(varA, Equals(varX, Real(8)))

        for solver in get_env().factory.all_solvers(logic=QF_LRA):
            res = get_implicant(f, solver_name=solver)
            self.assertIsNotNone(res, "Formula was expected to be SAT")
            self.assertValid(Implies(res, f), logic=QF_LRA)
Esempio n. 13
0
def solveDecisionProblem(filename):
	global robots_info
	global task_info
	global task_utilities
	global k
	robots_info = {}
	task_info = {}
	task_utilities = {}
	k=0

	file = open(filename, "r")
	mode = 0
	for line in file:
		if line=='\n':
			mode+=1
		elif mode==0:
			k = int(line.strip())
		elif mode==1:
			task_line = line.split()
			task_info[task_line[0]] = [int(resource) for resource in task_line[2:]]
			task_utilities[task_line[0]] = int(task_line[1])
		elif mode == 2:
			robot_line = line.split()
			robots_info[robot_line[0]] = [int(resource) for resource in robot_line[1:]]
	file.close()
		

	# Each robot may be assigned to at most one task
	# runs in time |Robots||Tasks||Tasks|
	oneTask = And([Symbol(robot+taskAssigned).Implies(Not(Symbol(robot+task))) for robot in robots_info.keys() for taskAssigned in task_info.keys() for task in task_info.keys() if (taskAssigned != task)])

	# A task is satisfied if and only if all of its resource requirements are met
	# runs in time |Robots||Tasks||ResourceTypes|
	tasksSatisfied = And([Iff(Symbol(task +"Sat"), And([GE(Plus([Times(Ite(Symbol(robot+task),Int(1), Int(0)), Int(robots_info[robot][i])) for robot in robots_info.keys()]), Int(task_info[task][i])) for i in range(len(task_info[task]))])) for task in task_info.keys()])

	# Is the decision problem satisfied
	# runs in time |Tasks|
	decisionProb = GE(Plus([Times(Ite(Symbol(task+"Sat"), Int(1), Int(0)), Int(task_utilities[task])) for task in task_info.keys()]), Int(k))

	prob = And(oneTask, tasksSatisfied, decisionProb)
	model = get_model(prob)
	return model
Esempio n. 14
0
    def add_lemmas(self, hts, prop, lemmas):
        if len(lemmas) == 0:
            return (hts, False)

        self._reset_assertions(self.solver)

        h_init = hts.single_init()
        h_trans = hts.single_trans()

        holding_lemmas = []
        lindex = 1
        nlemmas = len(lemmas)
        tlemmas = 0
        flemmas = 0
        for lemma in lemmas:
            Logger.log("\nChecking Lemma %s/%s" % (lindex, nlemmas), 1)
            invar = hts.single_invar()
            init = And(h_init, invar)
            trans = And(invar, h_trans, TS.to_next(invar))
            if self._check_lemma(hts, lemma, init, trans):
                holding_lemmas.append(lemma)
                hts.add_assumption(lemma)
                hts.reset_formulae()

                Logger.log("Lemma %s holds" % (lindex), 1)
                tlemmas += 1
                if self._suff_lemmas(prop, holding_lemmas):
                    return (hts, True)
            else:
                Logger.log("Lemma %s does not hold" % (lindex), 1)
                flemmas += 1

            msg = "%s T:%s F:%s U:%s" % (status_bar(
                (float(lindex) / float(nlemmas)), False), tlemmas, flemmas,
                                         (nlemmas - lindex))
            Logger.inline(msg, 0, not (Logger.level(1)))
            lindex += 1

        Logger.clear_inline(0, not (Logger.level(1)))

        hts.assumptions = And(holding_lemmas)
        return (hts, False)
Esempio n. 15
0
    def check_table_energies_exact(self, graph, decision_variables, h, J):
        """For a given ising problem, check that the table gives the correct
        energies when linear and quadratic energies are specified exactly.
        """

        # determine the aux variables
        aux_variables = tuple(v for v in graph if v not in decision_variables)

        # now generate a theta that sets linear and quadratic equal to h, J
        linear_ranges = {v: (bias, bias) for v, bias in h.items()}
        quadratic_ranges = {edge: (bias, bias) for edge, bias in J.items()}

        # and now the table
        table = Table(graph, decision_variables, linear_ranges, quadratic_ranges)

        # ok, time to do some energy calculations
        for config in itertools.product((-1, 1), repeat=len(decision_variables)):
            spins = dict(zip(decision_variables, config))

            # first we want to know the minimum classical energy
            energy = float('inf')
            for aux_config in itertools.product((-1, 1), repeat=len(aux_variables)):

                aux_spins = dict(zip(aux_variables, aux_config))
                aux_spins.update(spins)
                aux_energy = ising_energy(h, J, aux_spins)

                if aux_energy < energy:
                    energy = aux_energy

            # collect assertions
            assertions = table.assertions
            theta = table.theta  # so we can set the offset directly

            # table assertions by themselves should be SAT
            self.assertSat(And(assertions))

            # ok, does the exact energy calculated by the table match?
            table_energy = table.energy(spins, break_aux_symmetry=False)
            for offset in [0, -.5, -.3, -.1, .23, 1, 106]:

                self.assertSat(And([Equals(table_energy, limitReal(energy + offset)),
                                    And(assertions),
                                    Equals(theta.offset, limitReal(offset))]),
                               msg='exact energy equality is not SAT')
                self.assertUnsat(And([Not(Equals(table_energy, limitReal(energy + offset))),
                                      And(assertions),
                                      Equals(theta.offset, limitReal(offset))]),
                                 msg='exact energy inequality is not UNSAT')

            # how about the upper bound?
            table_energy_upperbound = table.energy_upperbound(spins)
            for offset in [-.5, -.3, -.1, 0, .23, 1, 106]:
                self.assertSat(And([GE(table_energy_upperbound, limitReal(energy + offset)),
                                    And(assertions),
                                    Equals(theta.offset, limitReal(offset))]),
                               msg='energy upperbound is not SAT')
Esempio n. 16
0
    def test_basic_expr(self):
        convert = self.bdd_converter.convert

        bdd_x = convert(self.x)
        bdd_y = convert(self.y)
        bdd_x_and_y = self.bdd_converter.ddmanager.And(bdd_x, bdd_y)

        x_and_y = And(self.x, self.y)
        converted_expr = convert(x_and_y)

        self.assertEqual(bdd_x_and_y, converted_expr)
Esempio n. 17
0
def generate_constraint_for_input_partition(input_partition):
    formula = None
    for var_name in input_partition:
        sym_array = Symbol(var_name, ArrayType(BV32, BV8))
        sym_var = BVConcat(
            Select(sym_array, BV(3, 32)),
            BVConcat(
                Select(sym_array, BV(2, 32)),
                BVConcat(Select(sym_array, BV(1, 32)),
                         Select(sym_array, BV(0, 32)))))
        constant_info = input_partition[var_name]
        upper_bound = int(constant_info['upper-bound'])
        lower_bound = int(constant_info['lower-bound'])
        sub_formula = And(BVSGE(SBV(upper_bound, 32), sym_var),
                          BVSLE(SBV(lower_bound, 32), sym_var))
        if formula is None:
            formula = sub_formula
        else:
            formula = And(formula, sub_formula)
    return formula
Esempio n. 18
0
    def test_solving_under_assumption(self):
        v1, v2 = [FreshSymbol() for _ in xrange(2)]
        xor = Or(And(v1, Not(v2)), And(Not(v1), v2))

        for name in get_env().factory.all_solvers():
            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())
Esempio n. 19
0
def generate_flipped_path(ppc):
    """
    This function will check if a selected path is feasible
           ppc : partial path conditoin at chosen control loc
           chosen_control_loc: branch location selected for flip
           returns satisfiability of the negated path
    """
    parser = SmtLibParser()
    new_path = None
    try:
        script = parser.get_script(cStringIO(ppc))
        formula = script.get_last_formula()
        prefix = formula.arg(0)
        constraint = formula.arg(1)
        new_path = And(prefix, Not(constraint))
        assert str(new_path.serialize()) != str(formula.serialize())
    except Exception as ex:
        emitter.debug("Pysmt parser error, skipping path flip")
    finally:
        return new_path
Esempio n. 20
0
    def test_pe_edge(self):
        sym_x = Symbol("x", REAL)  # child
        sym_y = Symbol("y", REAL)  # parent

        x_domain = And(sym_x > Real(-1), sym_x < Real(6))
        y_domain = And(sym_y > Real(-2), sym_y < Real(4))

        x = TNode(symbol=sym_x, label=1, domains=x_domain)
        y = TNode(symbol=sym_y, label=0, domains=y_domain)

        formula = LE(sym_x, sym_y + Real(1))
        edge = TEdge(parent=y, child=x, formula=formula)
        y.add_edge(edge)

        x_constraints = [[0, 1, 2], [2.5, 3.5, 4]]
        interval_and_degree = SMI.pe_edge(edge, x_constraints)
        self.assertListEqual(interval_and_degree[0], [-1.0, 0.0, 3])
        self.assertListEqual(interval_and_degree[1], [0, 1.5, 0])
        self.assertListEqual(interval_and_degree[2], [1.5, 2.5, 5])
        self.assertListEqual(interval_and_degree[3], [2.5, 4, 0])
Esempio n. 21
0
 def score_output(
     idx
 ):  #how many other outputs in the same amount that do not belong to us?
     outputs_equal_not_ours = [And(Equals(v,
                                          output_amt[idx]),
                                   Not(Equals(output_party[k],
                                              output_party[idx])))\
                               for (k, v) in filter(lambda x: x[0] != idx, output_amt.items())]
     score = Plus([bool_to_int(x) for x in outputs_equal_not_ours])
     anonymityset_constraints.add(Equals(output_score[idx], score))
     return score
Esempio n. 22
0
    def setUp(self):
        self.x, self.y = Symbol("x"), Symbol("y")

        self.bdd_solver = Solver(logic=pysmt.logics.BOOL, name='bdd')
        self.bdd_converter = self.bdd_solver.converter

        trail = [And, Or, And, Or]
        f = And(self.x, self.y)
        for op in trail:
            f = op(f, f)
        self.big_tree = f
Esempio n. 23
0
def check_in_language(tree_str, conf_file):
    cfg_f, cfg_r = read_features(conf_file)
    sent_t = Tree.parse(tree_str.strip(), trunc=False)
    symbols, all_constraints = get_sat_constraints(sent_t, cfg_f, cfg_r, {},
                                                   [])
    problem = And(all_constraints)
    model = get_model(problem)
    if model:
        return tree_to_str(sent_t)
    else:
        return None
Esempio n. 24
0
 def non_zero(self):
     w_reg_list = []
     for (weights, bias) in self.net_formula.values():
         for w_r, b in zip(weights, bias):
             for w in w_r:
                 coin = np.random.uniform(0, 1, 1)
                 if coin > 0.5:
                     w_reg_list.append(NotEquals(w, Real(0)))
             # w_reg_list.append(NotEquals(b, Real(0)))
     regularize = And(w_reg_list)
     return regularize
Esempio n. 25
0
    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 test_generic_wrapper_enable_debug(self):
        a = Symbol("A", BOOL)
        f = And(a, Not(a))

        for n in self.all_solvers:
            with Solver(name=n,
                        logic=QF_BOOL,
                        solver_options={'debug_interaction': True}) as s:
                s.add_assertion(f)
                res = s.solve()
                self.assertFalse(res)
Esempio n. 27
0
    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)
Esempio n. 28
0
    def test_ackermannization_binary(self):
        self.env.enable_infix_notation = True
        a, b = (Symbol(x, INT) for x in "ab")
        f, g = (Symbol(x, FunctionType(INT, [INT, INT])) for x in "fg")
        h = Symbol("h", FunctionType(INT, [INT]))

        formula1 = Not(Equals(f(a, g(a, h(a))), f(b, g(b, h(b)))))

        formula2 = Equals(a, b)
        formula = And(formula1, formula2)
        self._verify_ackermannization(formula)
Esempio n. 29
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)
Esempio n. 30
0
    def test_add_assertions(self):
        varA = Symbol("A", BOOL)
        varB = Symbol("B", BOOL)
        varC = Symbol("C", BOOL)

        assertions = [varA, Implies(varA, varB), Implies(varB, varC)]
        for name in get_env().factory.all_solvers(logic=QF_BOOL):
            with Solver(name) as solver:
                solver.add_assertions(assertions)
                solver.solve()
                self.assertTrue(solver.get_py_value(And(assertions)))
Esempio n. 31
0
        def check_step():
            self._reset_assertions(self.solver)
            self._add_assertion(self.solver, self.at_time(And(trans, lemma), 0))
            self._add_assertion(self.solver, self.at_time(Not(lemma), 1))

            if self._solve(self.solver):
                Logger.log("Lemma \"%s\" failed for L & T -> L'"%lemma, 2)
                return False

            Logger.log("Lemma \"%s\" holds for L & T -> L'"%lemma, 2)
            return True
Esempio n. 32
0
        def check_init():
            self._reset_assertions(self.solver)
            self._add_assertion(self.solver, self.at_time(And(init, Not(lemma)), 0), comment="Init check")
            res = self._solve(self.solver)

            if res:
                Logger.log("Lemma \"%s\" failed for I -> L"%lemma, 2)
                return False

            Logger.log("Lemma \"%s\" holds for I -> L"%lemma, 2)
            return True
Esempio n. 33
0
    def test_construction(self):
        """Build an eager model out of a dictionary"""

        x, y = FreshSymbol(), FreshSymbol()

        d = {x: TRUE(), y: FALSE()}

        model = EagerModel(assignment=d)

        self.assertEqual(model.get_value(x), TRUE())
        self.assertEqual(model.get_value(y), FALSE())
        self.assertEqual(model.get_value(And(x, y)), FALSE())
Esempio n. 34
0
def solve(formula, n, max_models=None, solver="msat"):
    s = Solver(name=solver)
    st = s.is_sat(formula)
    if st:
        vs = [x for xs in variables(n) for x in xs]
        k = 0
        s.add_assertion(formula)
        while s.solve() and ((not max_models) or k < max_models):
            k = k + 1
            model = s.get_model()
            s.add_assertion(Not(And([EqualsOrIff(v, model[v]) for v in vs])))
            yield to_bn(model, n)
Esempio n. 35
0
def is_global_circuit(f, c, sign=None):
    edges = list(zip(c, c[1:] + [c[0]]))
    k = len(c) + 1
    if sign == -1:
        # an odd number of edges are negative
        return Or([
            And([Or(edge(f, x, j, i, -1) for x in f) for j, i in ls] + [
                Or(edge(f, x, j, i, +1) for x in f)
                for j, i in edges if (j, i) not in ls
            ]) for m in range(1, k + 1, 2) for ls in combinations(edges, m)
        ])
    if sign == +1:
        # an even number of edges are negative
        return Or([
            And([Or(edge(f, x, j, i, -1) for x in f) for j, i in ls] + [
                Or(edge(f, x, j, i, +1) for x in f)
                for j, i in edges if (j, i) not in ls
            ]) for m in range(0, k + 1, 2) for ls in combinations(edges, m)
        ])
    # all edges exist
    return And([Not(And(edge(f, x, j, i, 0) for x in f)) for j, i in edges])
Esempio n. 36
0
    def test_ackermannization_dictionaries(self):
        self.env.enable_infix_notation = True
        a,b = (Symbol(x, INT) for x in "ab")
        f,g = (Symbol(x, FunctionType(INT, [INT, INT])) for x in "fg")
        h = Symbol("h", FunctionType(INT, [INT]))

        formula1 = Not(Equals(f(a, g(a, h(a))),
                              f(b, g(b, h(b)))))
        formula2 = Equals(a, b)
        formula = And(formula1, formula2)
        ackermannization = Ackermannizer()
        _ = ackermannization.do_ackermannization(formula)
        terms_to_consts = ackermannization.get_term_to_const_dict()
        consts_to_terms = ackermannization.get_const_to_term_dict()
        # The maps have the same length
        self.assertEqual(len(terms_to_consts), len(consts_to_terms))
        # The maps are the inverse of each other
        for t in terms_to_consts:
            self.assertEqual(t, consts_to_terms[terms_to_consts[t]])
        # Check that the the functions are there
        for atom in formula.get_atoms():
            if atom.is_function_application():
                self.assertIsNotNone(terms_to_consts[atom])
Esempio n. 37
0
    def test_basic(self):
        varA = Symbol("A")
        f = And(varA, Not(varA))

        self.assertEqual(f.size(), 4)
        self.assertEqual(f.size(SizeOracle.MEASURE_TREE_NODES), 4)
        self.assertEqual(f.size(SizeOracle.MEASURE_DAG_NODES), 3)
        self.assertEqual(varA.size(SizeOracle.MEASURE_LEAVES), 1)
        self.assertEqual(f.size(SizeOracle.MEASURE_DEPTH), 3)
        self.assertEqual(f.size(SizeOracle.MEASURE_SYMBOLS), 1)
Esempio n. 38
0
 def test_trivial_false_and(self):
     x,y,z = (Symbol(name) for name in "xyz")
     f = And(x, y, z, Not(x))
     self.assertEqual(f.simplify(), FALSE())
Esempio n. 39
0
 def test_and_flattening(self):
     x,y,z = (Symbol(name) for name in "xyz")
     f1 = And(x, y, z)
     f2 = And(x, And(y, z))
     self.assertEqual(f2.simplify(), f1)
Esempio n. 40
0
# Checking satisfiability of a formula.
#
# This example shows:
#  1. How to build a formula
#  2. How to perform substitution
#  3. Printing
#  4. Satisfiability checking
from pysmt.shortcuts import Symbol, And, Not, is_sat

varA = Symbol("A") # Default type is Boolean
varB = Symbol("B")
f = And([varA, Not(varB)])
g = f.substitute({varB:varA})

res = is_sat(f)
assert res # SAT
print("f := %s is SAT? %s" % (f, res))

res = is_sat(g)
print("g := %s is SAT? %s" % (g, res))
assert not res # UNSAT