Exemplo n.º 1
0
 def compute_reduced_core(self, i, j, val):
     """We compute the unsat core then remove any unnecessary terms."""
     if not (0 <= i <= 8 and 0 <= j <= 8 and 1 <= val <= 9):
         raise Exception(f'Index error: {i} {j} {val}')
     context = Context()
     self.assert_puzzle(context)
     self.assert_not_value(context, i, j, val)
     self.assert_trivial_rules(context)
     smt_stat = context.check_context_with_assumptions(
         None, self.duplicate_rules)
     # a valid puzzle should have a unique solution, so this should not happen, if it does we bail
     if smt_stat != Status.UNSAT:
         print(f'Error: {i} {j} {val} - not UNSAT: {Status.name(smt_stat)}')
         model = Model.from_context(context, 1)
         answer = self.puzzle_from_model(model)
         print(
             'Counter example (i.e. origonal puzzle does not have a unique solution):'
         )
         answer.pprint()
         model.dispose()
         context.dispose()
         return None
     core = context.get_unsat_core()
     filtered = core.copy()
     for term in core:
         filtered.remove(term)
         smt_stat = context.check_context_with_assumptions(None, filtered)
         if smt_stat != Status.UNSAT:
             filtered.append(term)
     context.dispose()
     print(
         f'Core: {i} {j} {val}   {len(filtered)} / {len(self.duplicate_rules)}'
     )
     return (i, j, val, filtered)
def pluck(puzzle, cardinality):

    # prepare our solver and context
    solver = Solver(puzzle)
    context = Context()
    solver.assert_rules(context)

    # start with a set of all 81 cells, and tries to remove one (randomly) at a time
    # but not before checking that the cell can still be deduced from the remaining cells.
    cells = set(range(81))
    cells_remaining = cells.copy()

    while len(cells) > cardinality and len(cells_remaining) != 0:
        cell = random.choice(list(cells_remaining))
        cells_remaining.discard(cell)
        row, column = cell // 9, cell % 9
        val = puzzle.get_cell(row, column)
        assert val is not None
        if solver.erasable(context, row, column, val):
            puzzle.erase_cell(row, column)
            cells.discard(cell)

    context.dispose()

    return (puzzle, len(cells))
Exemplo n.º 3
0
 def compute_core(self, i, j, val):
     """We compute the unsat core of the duplicate_rules when asserting self.var(i, j) != val w.r.t the puzzle (val is assumed to be the unique solution)."""
     if not (0 <= i <= 8 and 0 <= j <= 8 and 1 <= val <= 9):
         raise Exception(f'Index error: {i} {j} {val}')
     context = Context()
     self.assert_puzzle(context)
     self.assert_not_value(context, i, j, val)
     self.assert_trivial_rules(context)
     smt_stat = context.check_context_with_assumptions(
         None, self.duplicate_rules)
     # a valid puzzle should have a unique solution, so this should not happen, if it does we bail
     if smt_stat != Status.UNSAT:
         print(f'Error: {i} {j} {val} - not UNSAT: {Status.name(smt_stat)}')
         model = Model.from_context(context, 1)
         answer = self.puzzle_from_model(model)
         print(
             'Counter example (i.e. origonal puzzle does not have a unique solution):'
         )
         answer.pprint()
         model.dispose()
         context.dispose()
         return None
     core = context.get_unsat_core()
     context.dispose()
     print(
         f'Core: {i} {j} {val}   {len(core)} / {len(self.duplicate_rules)}')
     return (i, j, val, core)
Exemplo n.º 4
0
 def solve(self):
     context = Context()
     self.assert_rules(context)
     self.assert_puzzle(context)
     smt_stat = context.check_context(None)
     answer = None
     if smt_stat == Status.SAT:
         model = Model.from_context(context, 1)
         answer = self.puzzle_from_model(model)
         model.dispose()
     context.dispose()
     return answer
Exemplo n.º 5
0
 def filter_core(self, core):
     i, j, val, terms = core
     context = Context()
     self.assert_puzzle(context)
     self.assert_not_value(context, i, j, val)
     self.assert_trivial_rules(context)
     filtered = terms.copy()
     for term in terms:
         filtered.remove(term)
         smt_stat = context.check_context_with_assumptions(None, filtered)
         if smt_stat != Status.UNSAT:
             filtered.append(term)
     context.dispose()
     return (i, j, val, filtered)
    def delgado(self, delegate):

        if not Delegates.has_delegate(delegate):
            notify(f'delgado skipping missing delegate {delegate}\n')
            return

        formulas = make_formulas()

        bound = len(formulas) + 1

        for i in range(1, bound):
            config = Config()
            config.default_config_for_logic("QF_BV")
            context = Context(config)
            terms = truncate(formulas, i)
            context.assert_formulas(terms)
            status = context.check_context()
            notify(f'delgado status = {Status.name(status)} for i = {i}\n')
            self.assertEqual(status, Status.SAT if i < 3 else Status.UNSAT)
            config.dispose()
            context.dispose()


        for i in range(1, bound):
            model = []
            terms = truncate(formulas, i)
            status = Delegates.check_formulas(terms, "QF_BV", delegate, model)
            notify(f'delagdo({delegate}) status = {Status.name(status)} for i = {i}\n')
            self.assertEqual(status, Status.SAT if i < 3 else Status.UNSAT)
            if status is Status.SAT:
                notify(f'delagdo({delegate}) model = {model[0].to_string(80, 100, 0)} for i = {i}\n')
            else:
                self.assertEqual(len(model), 0)


        for i in range(1, bound):
            model = []
            term = conjoin(formulas, i)
            status = Delegates.check_formula(term, "QF_BV", delegate, model)
            notify(f'delagdo({delegate}) status = {Status.name(status)} for i = {i}\n')
            self.assertEqual(status, Status.SAT if i < 3 else Status.UNSAT)
            if status is Status.SAT:
                notify(f'delagdo({delegate}) model = {model[0].to_string(80, 100, 0)} for i = {i}\n')
            else:
                self.assertEqual(len(model), 0)
 def test_timeout(self):
     cfg = Config()
     cfg.default_config_for_logic('QF_NIA')
     ctx = Context(cfg)
     int_t = Types.int_type()
     [x, y, z] = [
         Terms.new_uninterpreted_term(int_t, id) for id in ['x', 'y', 'z']
     ]
     # x, y, z > 0
     for var in [x, y, z]:
         ctx.assert_formula(Terms.arith_gt0_atom(var))
     # x^3 + y^3 = z3
     [x3, y3, z3] = [Terms.product([var, var, var]) for var in [x, y, z]]
     lhs = Terms.sum([x3, y3])
     eq = Terms.arith_eq_atom(lhs, z3)
     ctx.assert_formula(eq)
     status = ctx.check_context(timeout=1)
     self.assertEqual(status, Status.INTERRUPTED)
     ctx.dispose()
     cfg.dispose()
 def test_context(self):
     cfg = Config()
     ctx = Context(cfg)
     stat = ctx.status()
     ret = ctx.push()
     ret = ctx.pop()
     ctx.reset_context()
     ret = ctx.enable_option("arith-elim")
     ret = ctx.disable_option("arith-elim")
     stat = ctx.status()
     self.assertEqual(stat, 0)
     ctx.reset_context()
     bool_t = Types.bool_type()
     bvar1 = Terms.new_variable(bool_t)
     with assertRaisesRegex(self, YicesException,
                            'assertion contains a free variable'):
         ctx.assert_formula(bvar1)
     bv_t = Types.bv_type(3)
     bvvar1 = Terms.new_uninterpreted_term(bv_t, 'x')
     bvvar2 = Terms.new_uninterpreted_term(bv_t, 'y')
     bvvar3 = Terms.new_uninterpreted_term(bv_t, 'z')
     fmla1 = Terms.parse_term('(= x (bv-add y z))')
     fmla2 = Terms.parse_term('(bv-gt y 0b000)')
     fmla3 = Terms.parse_term('(bv-gt z 0b000)')
     ctx.assert_formula(fmla1)
     ctx.assert_formulas([fmla1, fmla2, fmla3])
     smt_stat = ctx.check_context(None)
     self.assertEqual(smt_stat, Status.SAT)
     ctx.assert_blocking_clause()
     ctx.stop_search()
     param = Parameters()
     param.default_params_for_context(ctx)
     param.set_param("dyn-ack", "true")
     with assertRaisesRegex(self, YicesException, 'invalid parameter'):
         param.set_param("foo", "bar")
     with assertRaisesRegex(self, YicesException,
                            'value not valid for parameter'):
         param.set_param("dyn-ack", "bar")
     param.dispose()
     ctx.dispose()
    def test_dimacs(self):

        formulas = make_formulas()

        bound = len(formulas) + 1

        simplified = [None] * bound

        # first round, don't simplify the CNF
        for i in range(1, bound):
            simplify = False
            filename = f'/tmp/basic{1}.cnf'
            terms = truncate(formulas, i)

            file_ok, status = Dimacs.export_formulas(terms, filename, simplify)

            notify(
                f'Round 1: {file_ok}, {Status.name(status)} = export@{i}({terms}, {filename}, {simplify})\n'
            )

            if file_ok:
                self.assertEqual(os.path.exists(filename), True)
            else:
                self.assertEqual(status in [Status.SAT, Status.UNSAT], True)

            term = Terms.yand(terms)
            file_ok_c, status_c = Dimacs.export_formula(
                term, filename, simplify)

            notify(
                f'Round 1: {file_ok_c}, {Status.name(status_c)} = export@{i}({term}, {filename}, {simplify})\n'
            )

        # second round, simplify the CNF
        for i in range(1, bound):
            simplify = True
            filename = f'/tmp/simplify{i}.cnf'
            terms = truncate(formulas, i)

            file_ok, status = Dimacs.export_formulas(terms, filename, simplify)

            # save the status for later
            simplified[i] = status

            notify(
                f'Round 2: {file_ok}, {Status.name(status)} = export@{i}({terms}, {filename}, {simplify})\n'
            )

            if file_ok:
                self.assertEqual(os.path.exists(filename), True)
            else:
                self.assertEqual(status in [Status.SAT, Status.UNSAT], True)

            term = Terms.yand(terms)
            file_ok_c, status_c = Dimacs.export_formula(
                term, filename, simplify)

            notify(
                f'Round 2: {file_ok_c}, {Status.name(status_c)} = export@{i}({term}, {filename}, {simplify})\n'
            )

            self.assertEqual(status_c, simplified[i])

        # third round check the results
        for i in range(1, bound):
            config = Config()
            config.default_config_for_logic("QF_BV")
            context = Context(config)
            terms = truncate(formulas, i)
            context.assert_formulas(terms)
            status = context.check_context()
            notify(f'Round 3: status = {Status.name(status)} for i = {i}\n')
            self.assertEqual(status, simplified[i])
            config.dispose()
            context.dispose()
Exemplo n.º 10
0
class TestModels(unittest.TestCase):

    # pylint: disable=W0601

    def setUp(self):
        # this is required for some strange reason.
        # seems like yices/__init__.py does not get evaluated
        Yices.init()
        self.cfg = Config()
        self.ctx = Context(self.cfg)
        self.param = Parameters()
        self.param.default_params_for_context(self.ctx)
        global bool_t, int_t, real_t
        bool_t = Types.bool_type()
        int_t = Types.int_type()
        real_t = Types.real_type()

    def tearDown(self):
        self.cfg.dispose()
        self.ctx.dispose()
        self.param.dispose()
        Yices.exit()

    def test_bool_models(self):
        b1 = define_const('b1', bool_t)
        b2 = define_const('b2', bool_t)
        b3 = define_const('b3', bool_t)
        b_fml1 = Terms.parse_term('(or b1 b2 b3)')
        self.ctx.assert_formula(b_fml1)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        b_mdl1 = Model.from_context(self.ctx, 1)
        self.assertNotEqual(b_mdl1, None)
        bval1 = b_mdl1.get_bool_value(b1)
        bval2 = b_mdl1.get_bool_value(b2)
        bval3 = b_mdl1.get_bool_value(b3)
        self.assertEqual(bval1, False)
        self.assertEqual(bval2, False)
        self.assertEqual(bval3, True)
        b_fmla2 = Terms.parse_term('(not b3)')
        self.ctx.assert_formula(b_fmla2)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        b_mdl1 = Model.from_context(self.ctx, 1)
        self.assertNotEqual(b_mdl1, None)
        bval1 = b_mdl1.get_bool_value(b1)
        bval2 = b_mdl1.get_bool_value(b2)
        bval3 = b_mdl1.get_bool_value(b3)
        val1 = b_mdl1.get_value(b1)
        val2 = b_mdl1.get_value(b2)
        val3 = b_mdl1.get_value(b3)
        self.assertEqual(bval1, False)
        self.assertEqual(bval2, True)
        self.assertEqual(bval3, False)
        self.assertEqual(bval1, val1)
        self.assertEqual(bval2, val2)
        self.assertEqual(bval3, val3)

    def test_int_models(self):
        ''' int32, int64 '''
        i1 = define_const('i1', int_t)
        i2 = define_const('i2', int_t)
        assert_formula('(> i1 3)', self.ctx)
        assert_formula('(< i2 i1)', self.ctx)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        mdl = Model.from_context(self.ctx, 1)
        i32v1 = mdl.get_integer_value(i1)
        i32v2 = mdl.get_integer_value(i2)
        self.assertEqual(i32v1, 4)
        self.assertEqual(i32v2, 3)
        mdl.print_to_fd(1)
        mdl.print_to_fd(1, 80, 100, 0)
        mdlstr = mdl.to_string(80, 100, 0)
        self.assertEqual(mdlstr, '(= i1 4)\n(= i2 3)')

    def test_rat_models(self):
        ''' rational32, rational64, double '''
        r1 = define_const('r1', real_t)
        r2 = define_const('r2', real_t)
        assert_formula('(> r1 3)', self.ctx)
        assert_formula('(< r1 4)', self.ctx)
        assert_formula('(< (- r1 r2) 0)', self.ctx)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        mdl = Model.from_context(self.ctx, 1)
        v1 = mdl.get_fraction_value(r1)
        v2 = mdl.get_fraction_value(r2)
        # r1 = 7/2, r2 = 4/1
        self.assertEqual(v1.numerator, 7)
        self.assertEqual(v1.denominator, 2)
        self.assertEqual(v2.numerator, 4)
        self.assertEqual(v2.denominator, 1)
        rdoub1 = mdl.get_float_value(r1)
        rdoub2 = mdl.get_float_value(r2)
        self.assertEqual(rdoub1, 3.5)
        self.assertEqual(rdoub2, 4.0)
        val1 = mdl.get_value(r1)
        val2 = mdl.get_value(r2)
        self.assertEqual(val1, 3.5)
        self.assertEqual(val2, 4.0)

    def test_bv_models(self):
        bv_t = Types.bv_type(3)
        bv1 = define_const('bv1', bv_t)
        bv2 = define_const('bv2', bv_t)
        bv3 = define_const('bv3', bv_t)
        fmla1 = Terms.parse_term('(= bv1 (bv-add bv2 bv3))')
        fmla2 = Terms.parse_term('(bv-gt bv2 0b000)')
        fmla3 = Terms.parse_term('(bv-gt bv3 0b000)')
        self.ctx.assert_formula(fmla1)
        self.ctx.assert_formulas([fmla1, fmla2, fmla3])
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        mdl1 = Model.from_context(self.ctx, 1)
        val1 = mdl1.get_value(bv1)
        self.assertEqual(val1[0], 0)
        self.assertEqual(val1[1], 0)
        self.assertEqual(val1[2], 0)
        val2 = mdl1.get_value(bv2)
        self.assertEqual(val2[0], 0)
        self.assertEqual(val2[1], 0)
        self.assertEqual(val2[2], 1)
        val3 = mdl1.get_value(bv3)
        self.assertEqual(val3[0], 0)
        self.assertEqual(val3[1], 0)
        self.assertEqual(val3[2], 1)
        mdl1.dispose()

    def test_tuple_models(self):
        tup_t = Types.new_tuple_type([bool_t, real_t, int_t])
        t1 = define_const('t1', tup_t)
        assert_formula(
            '(ite (select t1 1) (< (select t1 2) (select t1 3)) (> (select t1 2) (select t1 3)))',
            self.ctx)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        mdl = Model.from_context(self.ctx, 1)
        mdlstr = mdl.to_string(80, 100, 0)
        self.assertEqual(mdlstr, '(= t1 (mk-tuple false 1 0))')
        val = mdl.get_value(t1)
        self.assertEqual(val[0], False)
        self.assertEqual(val[1], 1)
        self.assertEqual(val[2], 0)

    def test_model_from_map(self):
        bv_t = Types.bv_type(8)
        i1 = define_const('i1', int_t)
        r1 = define_const('r1', real_t)
        bv1 = define_const('bv1', bv_t)
        iconst1 = Terms.integer(42)
        rconst1 = Terms.rational(13, 131)
        bvconst1 = Terms.bvconst_integer(8, 134)
        mapping = {i1: iconst1, r1: rconst1, bv1: bvconst1}
        mdl = Model.from_map(mapping)
        mdlstr = mdl.to_string(80, 100, 0)
        self.assertEqual(mdlstr,
                         '(= i1 42)\n(= r1 13/131)\n(= bv1 0b10000110)')
        mdl.dispose()

    def test_implicant(self):
        i1 = define_const('i1', int_t)
        assert_formula('(and (> i1 2) (< i1 8) (/= i1 4))', self.ctx)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        mdl = Model.from_context(self.ctx, 1)
        mdlstr = mdl.to_string(80, 100, 0)
        self.assertEqual(mdlstr, '(= i1 7)')
        fml = Terms.parse_term('(>= i1 3)')
        tarray = mdl.implicant_for_formula(fml)
        self.assertEqual(len(tarray), 1)
        implstr = Terms.to_string(tarray[0], 200, 10, 0)
        self.assertEqual(implstr, '(>= (+ -3 i1) 0)')
        fml2 = Terms.parse_term('(<= i1 9)')
        tarray2 = mdl.implicant_for_formulas([fml, fml2])
        self.assertEqual(len(tarray2), 2)
        implstr2 = Terms.to_string(tarray2[0], 200, 10, 0)
        self.assertEqual(implstr2, '(>= (+ -3 i1) 0)')
        implstr3 = Terms.to_string(tarray2[1], 200, 10, 0)
        self.assertEqual(implstr3, '(>= (+ 9 (* -1 i1)) 0)')

    def test_scalar_models(self):
        scalar_t = Types.new_scalar_type(10)
        sc1 = define_const('sc1', scalar_t)
        sc2 = define_const('sc2', scalar_t)
        sc3 = define_const('sc3', scalar_t)
        assert_formula('(/= sc1 sc2)', self.ctx)
        assert_formula('(/= sc1 sc3)', self.ctx)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        mdl = Model.from_context(self.ctx, 1)
        val1 = mdl.get_scalar_value(sc1)
        val2 = mdl.get_scalar_value(sc2)
        val3 = mdl.get_scalar_value(sc3)
        self.assertEqual(val1, 9)
        self.assertEqual(val2, 8)
        self.assertEqual(val3, 8)
        self.assertEqual(Terms.is_scalar(sc1), True)
        sc1val = mdl.get_value_as_term(sc1)
        self.assertEqual(Terms.is_scalar(sc1val), True)
        self.assertEqual(mdl.get_value(sc1), sc1val)

    def test_function_models(self):
        funtype = Types.new_function_type([int_t, bool_t, real_t], real_t)
        ftystr = Types.to_string(funtype, 100, 80, 0)
        Types.print_to_fd(1, funtype, 100, 80, 0)
        self.assertEqual(ftystr, '(-> int bool real real)')
        fun1 = define_const('fun1', funtype)
        b1 = define_const('b1', bool_t)
        i1 = define_const('i1', int_t)
        r1 = define_const('r1', real_t)
        assert_formula(
            '(> (fun1 i1 b1 r1) (fun1 (+ i1 1) (not b1) (- r1 i1)))', self.ctx)
        self.assertEqual(self.ctx.check_context(self.param), Status.SAT)
        mdl = Model.from_context(self.ctx, 1)
        mdlstr = mdl.to_string(80, 100, 0)
        self.assertEqual(
            mdlstr,
            '(= b1 false)\n(= i1 1463)\n(= r1 -579)\n(function fun1\n (type (-> int bool real real))\n (= (fun1 1463 false -579) 1)\n (= (fun1 1464 true -2042) 0)\n (default 2))'
        )
        fun1val = mdl.get_value(fun1)
        self.assertEqual(fun1val((1463, False, -579)), 1)
        self.assertEqual(fun1val((1464, True, -2042)), 0)
        self.assertEqual(fun1val((1462, True, -2041)), 2)

    # pylint: disable=C0103
    def test_model_support(self):
        x = define_const('x', real_t)
        y = define_const('y', real_t)
        z = define_const('z', real_t)
        formula = Terms.parse_term('(> x 0)')
        t0 = Terms.parse_term('(ite (> x 0) (+ x z) y)')
        t1 = Terms.parse_term('(+ (* x z) y)')
        self.ctx.assert_formula(formula)
        self.assertEqual(self.ctx.check_context(), Status.SAT)
        mdl = Model.from_context(self.ctx, 1)
        support = mdl.support_for_term(t0)
        self.assertEqual(len(support), 2)
        self.assertEqual(support[0], x)
        self.assertEqual(support[1], z)
        support = mdl.support_for_terms([t0, t1])
        self.assertEqual(len(support), 3)
        self.assertEqual(support[0], x)
        self.assertEqual(support[1], y)
        self.assertEqual(support[2], z)
Exemplo n.º 11
0
set_value(context, (8, 3), 9)
set_value(context, (8, 7), 8)
set_value(context, (8, 9), 5)

set_value(context, (9, 1), 6)
set_value(context, (9, 2), 7)
set_value(context, (9, 3), 1)
set_value(context, (9, 7), 2)

#check sat

smt_stat = context.check_context(None)

if smt_stat != Status.SAT:
    print('No solution: smt_stat = {0}\n'.format(smt_stat))
else:
    #print model
    model = Model.from_context(context, 1)
    for i in range(9):
        for j in range(9):
            val = model.get_value(V(i, j))
            print('V({0}, {1}) = {2}'.format(i, j, val))
    model.dispose()

print('Cleaning up\n')

context.dispose()
config.dispose()

Yices.exit()
Exemplo n.º 12
0
class Solver(object):

    def __init__(self, diagram, protocol, verbose):
        self.diagram = diagram
        self.protocol = protocol
        self.verbose = verbose
        self.maxTimeStamp = diagram.max_timestamp
        print('Maximum time = {0}'.format(self.maxTimeStamp))
        self.context = Context()
        # assert that (b i) = b_i and (pt x y) = pt_x_y
        yassert_formulas(self, YicesSignature.toYicesTerms())


    def addFacts(self):
        if not self.addModel():
            return False
        self.protocol.constrainVariablesAPI(self.context)
        if not self.addProtocol():
            return False
        return True

    def addModel(self):
        # The last argument indicates that the theory should be completed.
        # Anything not asserted is asserted to be False.
        assertions = self.diagram.toYicesTerms(point=None, completeMe=True)
        if assertions is None:
            assertions = []
        retval =  yassert_formulas(self, assertions)
        if not retval:
            sys.stderr.write('addModel() failed\n')
        return retval

    def addProtocol(self):
        assertions = self.protocol.toYicesTerms(None, None, self.maxTimeStamp)
        if assertions is None:
            assertions = []
        retval = yassert_formulas(self, assertions)
        if not retval:
            sys.stderr.write('addProtocol() failed\n')
        return retval


    def getProtocolIncrementally(self, level):
        return self.protocol.toYicesTermsIncrementally(level)

    def writeTheory(self, theory_file):
        sb = StringBuffer()
        SymbolTable.toYices(sb)
        self.diagram.toYices(sb, None, True)
        self.protocol.toYices(sb, self.maxTimeStamp, False)
        theory = str(sb)
        string2File(theory, theory_file, False)
        string2File("(check)\n(show-model)\n", theory_file, True)



    def consistency_check(self):
        assertions = self.diagram.toYicesTerms(point=None, completeMe=True)
        alen = len(assertions)
        if alen:
            smt_stat = self.context.check_context_with_assumptions(None, assertions)
            sys.stderr.write('context.check_context_with_assumptions returned {0}\n'.format(Status.name(smt_stat)))
            if smt_stat == Status.SAT:
                #sys.stderr.write('Calling unsat_core on a satisfiable theory is user error\n')
                retcode = 0
            elif smt_stat == Status.UNSAT:
                unsat_core = self.context.get_unsat_core()
                if not unsat_core:
                    sys.stderr.write('unsat_core is empty\n')
                else:
                    print("\nUnsat core:\n")
                    for term in unsat_core:
                        Terms.print_to_fd(1, term, 80, 100, 0)
                    print("\n")
            else:
                retcode = 1
            retcode = 0
        self._cleanUp()
        return retcode


    # a retcode of 0 means the problem is SAT
    # a retcode of 1 means the problem is UNSAT
    # a retcode of 2 means there was an error somewhere
    def solve(self, theory_file):
        retcode = 2
        if not self.addFacts():
            return retcode
        if theory_file is not None:
            self.writeTheory(theory_file)
        smt_stat = self.context.check_context()
        if smt_stat != Status.SAT:
            print('No solution: smt_stat = {0}\n'.format(smt_stat))
            retcode = 1
        else:
            print('\nSatisfiable.')
            #get the model
            model = Model.from_context(self.context, 1)
            self.print_solution(model)
            model.dispose()
            retcode = 0
        self._cleanUp()
        return retcode




    def incrementally_solve(self):
        retcode = 2
        if not self.addModel():
            return retcode
        self.protocol.constrainVariablesAPI(self.context)
        if self.context.status() == Status.UNSAT:
            print('The model appears to be UNSAT: smt_stat = {}\n'.format(self.context.status()))
            print('For more information use the --consistency option.\n')
            return retcode
        # The meaning of the levels:
        #
        # 0.  Just the events
        # 1.  The events plus the distinctness of each timeline:  distinct(varlist) for timeline(bot, varlist) in facts.
        # 2.  The events plus the ascendingness of each timeline
        for level in range(0, 4):
            #print('context status: ', Status.name(self.context.status()))
            self.context.push()
            assertions = self.getProtocolIncrementally(level)
            alen = len(assertions)
            if alen:
                smt_stat = self.context.check_context_with_assumptions(None, assertions)
                sys.stderr.write('Level {0}: context.check_context_with_assumptions returned {1}\n'.format(level, Status.name(smt_stat)))
                if smt_stat == Status.SAT:
                    #get the model
                    model = Model.from_context(self.context, 1)
                    print('Level {0} has a solution: smt_stat = {1}\n'.format(level, smt_stat))
                    self.print_solution(model)
                    model.dispose()
                elif smt_stat == Status.UNSAT:
                    unsat_core = self.context.get_unsat_core()
                    if not unsat_core:
                        sys.stderr.write('unsat_core is empty\n')
                    else:
                        print('Level {0} unsat core is:\n'.format(level))
                        for term in unsat_core:
                            Terms.print_to_fd(1, term, 80, 100, 0)
                        print('')
                    return 0
                else:
                    sys.stderr.write('context.check_context_with_assumptions returned {0}\n'.format(Status.name(smt_stat)))
            self.context.pop()
        self._cleanUp()
        return 0


    def exhaust(self):
        result = 0
        self.context.push()
        if not self.addFacts():
            print('Bummer')
            return 2
        # BD says: this is complete but crude
        # another way would be to use 'yices_assert_blocking_clause'
        while  self.context.check_context() == Status.SAT:
            model = Model.from_context(self.context, 1)
            self.print_solution(model, 'Model #{0}:'.format(result))
            diagram = YicesSignature.model2term(model)
            self.context.assert_formula(Terms.ynot(diagram))
            model.dispose()
            result += 1
            if result == Configuration.aleph_nought:
                break
        self.context.pop()
        print("I found {1} distinct model{2} (using an upper limit of {0})".format(Configuration.aleph_nought, result, "" if result == 1 else "s"))
        return result



    def unsat_core(self):
        retcode = 2
        if not self.addModel():
            sys.stderr.write('addModel failed\n')
            return retcode
        self.protocol.constrainVariablesAPI(self.context)
        smt_stat = self.context.check_context()
        #sys.stderr.write('context.check_context returned {0}\n'.format(Status.name(smt_stat)))
        if smt_stat == Status.UNSAT:
            sys.stderr.write('The model is UNSAT: something is rotten in the State\n')
            retcode = 1
            return retcode
        assertions = self.protocol.toYicesTerms()
        alen = len(assertions)
        if alen:
            smt_stat = self.context.check_context_with_assumptions(None, assertions)
            sys.stderr.write('context.check_context_with_assumptions returned {0}\n'.format(Status.name(smt_stat)))
            if smt_stat == Status.SAT:
                sys.stderr.write('Calling unsat_core on a satisfiable theory is user error\n')
                retcode = 1
            elif smt_stat == Status.UNSAT:
                unsat_core = self.context.get_unsat_core()
                if not unsat_core:
                    sys.stderr.write('unsat_core is empty\n')
                else:
                    for term in unsat_core:
                        Terms.print_to_fd(1, term, 80, 100, 0)
            else:
                retcode = 1
            retcode = 0
        self._cleanUp()
        return retcode


    def missing(self):
        retcode = 2
        if not self.addModel():
            sys.stderr.write('addModel failed\n')
            return retcode
        self.protocol.constrainVariablesAPI(self.context)
        timelines = self.protocol.timelines
        tlen = len(timelines)
        interpretation = Configuration.timeline_interpretation
        tint_text = Configuration.INTERPRETATIONS[interpretation]
        print('There are {0} timelines ({1})\n'.format(tlen, tint_text))
        if not timelines:
            return retcode
        for timeline in timelines:
            formula = timeline.toYicesTerm(interpretation)
            yassert_formula(self, formula)
        smt_stat = self.context.check_context()
        if smt_stat == Status.UNSAT:
            sys.stderr.write('The model is UNSAT: something is rotten in the State\n')
            retcode = 1
            return retcode
        for timeline in timelines:
            satisfiable = True
            yevents = [ ]
            for eindex, timevar in enumerate(timeline.varlist):
                events = self.protocol.event_map[timevar]
                for e in events:
                    yevents.append(e.yices_term)
                smt_stat = self.context.check_context_with_assumptions(None, yevents)
                if smt_stat == Status.UNSAT:
                    satisfiable = False
                    print('UNSAT at level {0}, i.e. timestamp {1}'.format(eindex, timevar))
                    unsat_core = self.context.get_unsat_core()
                    print("\nUnsat core :\n")
                    for term in unsat_core:
                        Terms.print_to_fd(1, term, 80, 100, 0)
                    print("\n")
                    break
                elif self.verbose and smt_stat == Status.SAT:
                    print('SAT at level {0}, i.e. timestamp {1}'.format(eindex, timevar))
                    model = Model.from_context(self.context, 1)
                    self.print_solution(model, header=None, frees=timeline.fv)
                    model.dispose()
            if satisfiable:
                print('Timeline of {0} OK ({1}):\n'.format(timeline.term, tint_text))  #print a model
                model = Model.from_context(self.context, 1)
                self.print_solution(model, header=None, frees=timeline.fv)
                model.dispose()
        retcode = 0
        self._cleanUp()
        return retcode



    def print_solution(self, model, header=None, frees=None):

        def print_int(v):
            ytvar = v.yices_term
            ytval = model.get_value(ytvar)
            print('\t{0} is {1}'.format(v.name, ytval))


        if header is not None:
            print(header)

        if frees is None:
            nv = YicesSignature.get_vars(SymbolTable.NAT)
            for nvar in nv:
                print_int(nvar)
            tv = YicesSignature.get_vars(SymbolTable.TIME)
            for tvar in tv:
                if tvar.name == SymbolTable.MAXTIME:
                    continue
                print_int(tvar)
            pv = YicesSignature.get_vars(SymbolTable.PT2)
            for ptvar in pv:
                if ptvar.name == SymbolTable.NOLOC:
                    continue
                ytvar = ptvar.yices_term
                ytval = model.get_value(ytvar)
                val = YicesSignature.pt2_invmap[ytval]
                print('\t{0} is {1}'.format(ptvar.name, val))
        else:
            frees = list(frees)
            frees.sort()
            for var in frees:
                ytvar = var.yices_term
                ytval = model.get_value(ytvar)
                if var.vartype.name == 'Pt2':
                    ytval = YicesSignature.pt2_invmap[ytval]
                print('\t{0} is {1}'.format(var.name, ytval))


    def frontier(self):
        retcode = 2
        if not self.addModel():
            return retcode
        self.protocol.constrainVariablesAPI(self.context)
        searchSpace = Frontier(self.protocol)
        interpretation = Configuration.timeline_interpretation
        tint_text = Configuration.INTERPRETATIONS[interpretation]
        print('The timeline interpretation is: {0}\n'.format(tint_text))
        while not searchSpace.finished():
            point = searchSpace.nextElement()
            if point is None:
                break
            if self.verbose:
                print(point)
            assertions = self.protocol.toYicesTerms(point)
            alen = len(assertions)
            if alen:
                smt_stat = self.context.check_context_with_assumptions(None, assertions)
                if smt_stat == Status.SAT:
                    if self.verbose:
                        print('SAT')
                        #get the model
                        model = Model.from_context(self.context, 1)
                        self.print_solution(model, header=None, frees=self.protocol.FV(point))
                        model.dispose()
                elif smt_stat == Status.UNSAT:
                    searchSpace.addUnsat(point)
                    if self.verbose:
                        print('UNSAT')
                        unsat_core = self.context.get_unsat_core()
                        print("\nUnsat core:\n")
                        for term in unsat_core:
                            Terms.print_to_fd(1, term, 80, 100, 0)
                        print("\n")
            else:
                sys.stderr.write('context.check_context_with_assumptions returned {0}\n', smt_stat)
        print('Frontier: {0}'.format(searchSpace.frontier))
        self._cleanUp()
        return retcode


    def entire(self):
        retcode = 2
        if not self.addModel():
            return retcode
        self.protocol.constrainVariablesAPI(self.context)
        searchSpace = Frontier(self.protocol)
        tower = list(searchSpace.tower())
        tower.sort()
        for point in tower:
            print(point)
            assertions = self.protocol.toYicesTerms(point)
            alen = len(assertions)
            if alen:
                smt_stat = self.context.check_context_with_assumptions(None, assertions)
                if smt_stat == Status.SAT:
                    print('SAT')
                    #get the model
                    model = Model.from_context(self.context, 1)
                    self.print_solution(model, header=None, frees=self.protocol.FV(point))
                    model.dispose()
                elif smt_stat == Status.UNSAT:
                    print('UNSAT')
                    unsat_core = self.context.get_unsat_core()
                    print("\nUnsat core:\n")
                    for term in unsat_core:
                        Terms.print_to_fd(1, term, 80, 100, 0)
                    print("\n")
                else:
                    sys.stderr.write('context.check_context_with_assumptions returned {0}\n', smt_stat)
        self._cleanUp()
        return retcode




    def _cleanUp(self):
        self.context.dispose()
        Yices.exit()