Example #1
0
    def testDatatypeNat(self):
        basic.load_theory('logic_base')
        nat_item = items.parse_item({
            "args": [],
            "constrs": [{
                "args": [],
                "name": "zero",
                "type": "nat"
            }, {
                "args": ["n"],
                "name": "Suc",
                "type": "nat => nat"
            }],
            "name":
            "nat",
            "ty":
            "type.ind"
        })
        self.assertIsNone(nat_item.error)
        ext = nat_item.get_extension()
        theory.thy.unchecked_extend(ext)
        ext_output = [
            "Type nat 0", "Constant zero :: nat", "Constant Suc :: nat => nat",
            "Theorem nat_zero_Suc_neq: ~(0 = Suc n)",
            "Theorem nat_Suc_inject: Suc n = Suc n1 --> n = n1",
            "Theorem nat_induct: P 0 --> (!n. P n --> P (Suc n)) --> P x",
            "Attribute nat_induct [var_induct]"
        ]

        with global_setting(unicode=False):
            self.assertEqual(printer.print_extensions(ext),
                             '\n'.join(ext_output))
Example #2
0
    def testDatatypeList(self):
        basic.load_theory('logic_base')
        list_item = items.parse_item({
            "args": ["a"],
            "constrs": [{
                "args": [],
                "name": "nil",
                "type": "'a list"
            }, {
                "args": ["x", "xs"],
                "name": "cons",
                "type": "'a => 'a list => 'a list"
            }],
            "name":
            "list",
            "ty":
            "type.ind"
        })
        self.assertIsNone(list_item.error)
        ext = list_item.get_extension()
        theory.thy.unchecked_extend(ext)
        ext_output = [
            "Type list 1", "Constant nil :: 'a list",
            "Constant cons :: 'a => 'a list => 'a list",
            "Theorem list_nil_cons_neq: ~([] = x # xs)",
            "Theorem list_cons_inject: x # xs = x1 # xs1 --> x = x1 & xs = xs1",
            "Theorem list_induct: P [] --> (!x1. !xs. P xs --> P (x1 # xs)) --> P x",
            "Attribute list_induct [var_induct]"
        ]

        with global_setting(unicode=False):
            self.assertEqual(printer.print_extensions(ext),
                             '\n'.join(ext_output))
Example #3
0
    def testPredEven(self):
        basic.load_theory('nat', limit=('def', 'one'))
        even_item = items.parse_item({
            "name":
            "even",
            "rules": [{
                "name": "even_zero",
                "prop": "even 0"
            }, {
                "name": "even_Suc",
                "prop": "even n --> even (Suc (Suc n))"
            }],
            "ty":
            "def.pred",
            "type":
            "nat => bool"
        })
        self.assertIsNone(even_item.error)
        ext = even_item.get_extension()
        theory.thy.unchecked_extend(ext)
        ext_output = [
            "Constant even :: nat => bool", "Theorem even_zero: even 0",
            "Attribute even_zero [hint_backward]",
            "Theorem even_Suc: even n --> even (Suc (Suc n))",
            "Attribute even_Suc [hint_backward]",
            "Theorem even_cases: even _a1 --> (_a1 = 0 --> P) --> (!n. _a1 = Suc (Suc n) --> even n --> P) --> P"
        ]

        with global_setting(unicode=False):
            self.assertEqual(printer.print_extensions(ext),
                             '\n'.join(ext_output))
Example #4
0
    def testParseType(self):
        test_data = [
            "'b",
            "?'b",
            "nat",
            "'a list",
            "nat list",
            "nat list list",
            "'a => 'b",
            "'a => 'b => 'c",
            "('a => 'b) => 'c",
            "('a => 'b) => 'c => 'd",
            "(('a => 'b) => 'c) => 'd",
            "?'a => ?'b",
            "'a => 'b list",
            "('a => 'b) list",
            "'a list list",
            "'a list => 'b list",
            "('a list => 'b) list",
        ]

        basic.load_theory('list')
        for s in test_data:
            T = parser.parse_type(s)
            self.assertIsInstance(T, Type)
            with global_setting(unicode=False):
                self.assertEqual(str(T), s)
Example #5
0
def check_modify():
    """Check a modified item for validity.
    
    Input:
    * username: username.
    * filename: name of the file.
    * line_length: maximum length of printed line.
    * item: item to be checked.

    Returns:
    * checked item.

    """
    data = json.loads(request.get_data().decode("utf-8"))
    username = data['username']
    edit_item = data['item']
    line_length = data.get('line_length')

    if 'limit_ty' in data:
        limit = (data['limit_ty'], data['limit_name'])
    else:
        limit = None

    basic.load_theory(data['filename'], limit=limit, username=username)

    item = items.parse_edit(edit_item)
    if item.error is None:
        theory.thy.unchecked_extend(item.get_extension())
    with settings.global_setting(line_length=line_length):
        output_item = item.export_web()

    return jsonify({'item': output_item})
Example #6
0
    def testDatatypeProd(self):
        basic.load_theory('logic_base')
        prod_item = items.parse_item({
            "args": ["a", "b"],
            "constrs": [{
                "args": ["a", "b"],
                "name": "Pair",
                "type": "'a => 'b => ('a, 'b) prod"
            }],
            "name":
            "prod",
            "ty":
            "type.ind"
        })
        self.assertIsNone(prod_item.error)
        ext = prod_item.get_extension()
        theory.thy.unchecked_extend(ext)
        ext_output = [
            "Type prod 2", "Constant Pair :: 'a => 'b => ('a, 'b) prod",
            "Theorem prod_Pair_inject: Pair a b = Pair a1 b1 --> a = a1 & b = b1",
            "Theorem prod_induct: (!a. !b. P (Pair a b)) --> P x",
            "Attribute prod_induct [var_induct]"
        ]

        with global_setting(unicode=False):
            self.assertEqual(printer.print_extensions(ext),
                             '\n'.join(ext_output))
Example #7
0
    def testOpenEmpty(self):
        basic.load_theory('topology')

        st = auto.init_proof_theorem('open_empty')
        st.step_for(20, debug=False)
        self.assertEqual(st.step_count, 7)
        self.assertEqual(len(st.updates), 6)
Example #8
0
    def testLoadTheory(self):
        thy1 = basic.load_theory('logic_base')
        thy2 = basic.load_theory('logic')

        self.assertEqual(thy1.get_theorem('conjI'), thy2.get_theorem('conjI'))
        self.assertRaises(TheoryException, thy1.get_theorem, 'conj_comm')
        self.assertIsInstance(thy2.get_theorem('conj_comm'), Thm)
Example #9
0
    def testFunPlus(self):
        basic.load_theory('nat', limit=('def', 'one'))
        plus_item = items.parse_item({
            "name":
            "plus",
            "rules": [{
                "prop": "0 + n = n"
            }, {
                "prop": "Suc m + n = Suc (m + n)"
            }],
            "ty":
            "def.ind",
            "type":
            "nat ⇒ nat ⇒ nat"
        })
        self.assertIsNone(plus_item.error)
        ext = plus_item.get_extension()
        theory.thy.unchecked_extend(ext)
        ext_output = [
            "Constant plus :: nat => nat => nat",
            "Theorem plus_def_1: 0 + n = n",
            "Attribute plus_def_1 [hint_rewrite]",
            "Theorem plus_def_2: Suc m + n = Suc (m + n)",
            "Attribute plus_def_2 [hint_rewrite]"
        ]

        with global_setting(unicode=False):
            self.assertEqual(printer.print_extensions(ext),
                             '\n'.join(ext_output))
Example #10
0
def testSteps(self, thy_name, thm_name, *, no_gaps=True, print_proof=False, \
              print_stat=False, print_search=False, print_steps=False):
    """Test list of steps for the given theorem."""
    def test_val(val):
        context.set_context(None, vars=val['vars'])
        state = server.parse_init_state(val['prop'])
        goal = state.prf.items[-1].th
        num_found = 0
        if print_stat and 'steps' not in val:
            print("%20s %s" % (val['name'], "No steps found"))
            return

        for i, step in enumerate(val['steps']):
            if print_search or print_stat:
                if 'fact_ids' not in step:
                    step['fact_ids'] = []
                if print_steps:
                    print(method.output_step(state, step))
                if print_search:
                    select_ids = "goal " + step['goal_id']
                    if step['fact_ids']:
                        select_ids += ", fact " + ", ".join(step['fact_ids'])
                    print('Step ' + str(i) + " (" + select_ids + ")")
                search_res = state.search_method(step['goal_id'],
                                                 step['fact_ids'])
                found = 0
                for res in search_res:
                    m = method.global_methods[res['method_name']]
                    if res['method_name'] == step['method_name'] and \
                       all(sig not in res or sig not in step or res[sig] == step[sig] for sig in m.sig):
                        if print_search:
                            print('* ' + m.display_step(state, res))
                        found += 1
                    else:
                        if print_search:
                            print('  ' + m.display_step(state, res))
                assert found <= 1, "test_val: multiple found"
                if found == 0:
                    if print_search:
                        m = method.global_methods[step['method_name']]
                        print('- ' + m.display_step(state, step))
                else:
                    num_found += 1
            method.apply_method(state, step)
        self.assertEqual(state.check_proof(no_gaps=no_gaps), goal)
        if print_proof:
            print("Final state:")
            print(state.prf)
        if print_stat:
            total = len(val['steps'])
            print("%20s %5d %5d %5d" %
                  (val['name'], total, num_found, total - num_found))

    basic.load_theory(thy_name, limit=('thm', thm_name))
    with open('./library/' + thy_name + '.json', 'r', encoding='utf-8') as f:
        f_data = json.load(f)
        for val in f_data['content']:
            if val['ty'] == 'thm' and val['name'] == thm_name:
                test_val(val)
Example #11
0
 def setUp(self):
     basic.load_theory('list')
     context.ctxt = context.Context(vars={
         "A" : BoolType,
         "P" : TFun(Ta, BoolType),
         "a" : Ta,
         "b" : Ta,
     })
Example #12
0
    def testParseUnicodeType(self):
        test_data = ["'a ⇒ 'b"]

        basic.load_theory('list')
        for s in test_data:
            T = parser.parse_type(s)
            self.assertIsInstance(T, Type)
            with global_setting(unicode=True):
                self.assertEqual(print_type(T), s)
Example #13
0
def search_method():
    """Match for applicable methods and their arguments.
    
    Input:
    * username: username.
    * theory_name: name of the theory.
    * thm_name: name of the theorem.

    Returns:
    * search_res: list of search results.
    * ctxt: current proof context.

    """
    data = json.loads(request.get_data().decode("utf-8"))

    if data['profile']:
        pr = cProfile.Profile()
        pr.enable()

    if not proof_cache.check_cache(data):
        start_time = time.perf_counter()
        proof_cache.create_cache(data)
        print("Load: %f" % (time.perf_counter() - start_time))

    if data['thm_name'] != '':
        limit = ('thm', data['thm_name'])
    else:
        limit = None
    basic.load_theory(data['theory_name'],
                      limit=limit,
                      username=data['username'])

    start_time = time.perf_counter()
    state = proof_cache.states[data['index']]
    fact_ids = data['step']['fact_ids']
    goal_id = data['step']['goal_id']

    search_res = state.search_method(goal_id, fact_ids)
    with settings.global_setting(unicode=True):
        for res in search_res:
            if '_goal' in res:
                res['_goal'] = [printer.print_term(t) for t in res['_goal']]
            if '_fact' in res:
                res['_fact'] = [printer.print_term(t) for t in res['_fact']]

    vars = state.get_vars(goal_id)
    with settings.global_setting(unicode=True, highlight=True):
        print_vars = dict((k, printer.print_type(v)) for k, v in vars.items())
    print("Response:", time.perf_counter() - start_time)

    if data['profile']:
        p = Stats(pr)
        p.strip_dirs()
        p.sort_stats('cumtime')
        p.print_stats()

    return jsonify({'search_res': search_res, 'ctxt': print_vars})
Example #14
0
 def testLoadTheoryWithLimit(self):
     thy = basic.load_theory('logic_base')
     thy1 = basic.load_theory('logic_base', limit=('thm.ax', 'conjD1'))
     self.assertEqual(thy.get_theorem('conjI'), thy1.get_theorem('conjI'))
     self.assertRaises(TheoryException, thy1.get_theorem, 'conjD1')
     self.assertRaises(AssertionError,
                       basic.load_theory,
                       'logic_base',
                       limit=('thm.ax', 'conj'))
Example #15
0
    def testPrintString(self):
        test_data = [
            (string.mk_char('c'), "'c'"),
            (string.mk_string("ab"), '"ab"'),
        ]

        basic.load_theory('string')
        for t, s in test_data:
            self.assertEqual(printer.print_term(t), s)
Example #16
0
    def testPrintInterval(self):
        m = Var("m", NatType)
        n = Var("n", NatType)
        test_data = [
            (interval.mk_interval(m, n), "{m..n}"),
            (interval.mk_interval(nat.one, m), "{1..m}"),
        ]

        basic.load_theory('iterate')
        for t, s in test_data:
            self.assertEqual(printer.print_term(t), s)
Example #17
0
    def testParseTypeInd(self):
        test_data = [
            ("cons (x ::'a) (xs ::'a list)", {
                'name': 'cons',
                'type': [TVar('a'), TConst('list', TVar('a'))],
                'args': ['x', 'xs']
            }),
        ]

        basic.load_theory('list')
        for s, res in test_data:
            self.assertEqual(parser.parse_ind_constr(s), res)
Example #18
0
 def testInduct2(self):
     basic.load_theory('list')
     xs = Var("xs", parser.parse_type("'a list"))
     self.run_test(
         'list',
         tactic.var_induct(),
         vars={"xs": "'a list"},
         goal="xs @ [] = xs",
         args=("list_induct", xs),
         new_goals=[
             "([]::'a list) @ [] = []",
             "!x::'a. !xs. xs @ [] = xs --> (x # xs) @ [] = x # xs"
         ])
Example #19
0
    def testPrintReal(self):
        basic.load_theory('real')

        m = Var("m", RealType)
        test_data = [
            (real.zero, "(0::real)"),
            (real.one, "(1::real)"),
            (Real(2), "(2::real)"),
            (Real(3), "(3::real)"),
            (real.plus(m, real.one), "m + 1"),
            (real.plus(real.one, Real(2)), "(1::real) + 2"),
        ]

        for t, s in test_data:
            self.assertEqual(printer.print_term(t), s)
Example #20
0
    def testPrintInt(self):
        basic.load_theory('int')

        m = Var("m", IntType)
        test_data = [
            (Int(0), "(0::int)"),
            (Int(1), "(1::int)"),
            (Int(2), "(2::int)"),
            (Int(3), "(3::int)"),
            (m + 1, "m + 1"),
            (Int(1) + 2, "(1::int) + 2"),
        ]

        for t, s in test_data:
            self.assertEqual(printer.print_term(t), s)
Example #21
0
    def testDisjCommWithMacro(self):
        """Proof of commutativity of disjunction, with macros."""
        thy = basic.load_theory('logic_base')
        A = Var("A", boolT)
        B = Var("B", boolT)
        disjAB = logic.mk_disj(A, B)
        disjBA = logic.mk_disj(B, A)

        prf = Proof(disjAB)
        prf.add_item(1, "assume", args=A)
        prf.add_item(2,
                     "apply_theorem_for",
                     args=("disjI2", {}, {
                         "A": B,
                         "B": A
                     }),
                     prevs=[1])
        prf.add_item(3, "implies_intr", args=A, prevs=[2])
        prf.add_item(4, "assume", args=B)
        prf.add_item(5,
                     "apply_theorem_for",
                     args=("disjI1", {}, {
                         "A": B,
                         "B": A
                     }),
                     prevs=[4])
        prf.add_item(6, "implies_intr", args=B, prevs=[5])
        prf.add_item(7, "apply_theorem", args="disjE", prevs=[0, 3, 6])
        prf.add_item(8, "implies_intr", args=disjAB, prevs=[7])
        th = Thm.mk_implies(disjAB, disjBA)
        self.assertEqual(thy.check_proof(prf), th)
Example #22
0
    def testDoubleNegInv(self):
        """Proof of ~~A --> A, requires classical axiom."""
        thy = basic.load_theory('logic_base')
        A = Var("A", boolT)
        neg = logic.neg

        prf = Proof(neg(neg(A)))
        prf.add_item(1, "theorem", args="classical")
        prf.add_item(2, "assume", args=A)
        prf.add_item(3, "assume", args=neg(A))
        prf.add_item(4, "theorem", args="negE")
        prf.add_item(5, "substitution", args={"A": neg(A)}, prevs=[4])
        prf.add_item(6, "implies_elim", prevs=[5, 0])
        prf.add_item(7, "implies_elim", prevs=[6, 3])
        prf.add_item(8, "theorem", args="falseE")
        prf.add_item(9, "implies_elim", prevs=[8, 7])
        prf.add_item(10, "implies_intr", args=A, prevs=[2])
        prf.add_item(11, "implies_intr", args=neg(A), prevs=[9])
        prf.add_item(12, "theorem", args="disjE")
        prf.add_item(13,
                     "substitution",
                     args={
                         "B": neg(A),
                         "C": A
                     },
                     prevs=[12])
        prf.add_item(14, "implies_elim", prevs=[13, 1])
        prf.add_item(15, "implies_elim", prevs=[14, 10])
        prf.add_item(16, "implies_elim", prevs=[15, 11])
        prf.add_item(17, "implies_intr", args=neg(neg(A)), prevs=[16])
        th = Thm.mk_implies(neg(neg(A)), A)
        self.assertEqual(thy.check_proof(prf), th)
Example #23
0
 def testApplyInduction(self):
     thy = basic.load_theory('nat')
     n = Var("n", nat.natT)
     state = ProofState.init_state(thy, [n], [], Term.mk_equals(nat.plus(n, nat.zero), n))
     state.apply_induction(0, "nat_induct", "n")
     self.assertEqual(state.check_proof(), Thm([], Term.mk_equals(nat.plus(n, nat.zero), n)))
     self.assertEqual(len(state.prf.items), 3)
Example #24
0
 def testAddZeroRightWithMacro(self):
     """Proof of n + 0 = n by induction, using macros."""
     thy = basic.load_theory('nat')
     n = Var("n", nat.natT)
     eq = Term.mk_equals
     plus = nat.plus
     zero = nat.zero
     S = nat.Suc
     prf = Proof()
     prf.add_item(0, "reflexive", args=zero)
     prf.add_item(1,
                  "rewrite_goal",
                  args=("plus_def_1", eq(plus(zero, zero), zero)),
                  prevs=[0])
     prf.add_item(2, "assume", args=eq(plus(n, zero), n))
     prf.add_item(3, "arg_combination", args=S, prevs=[2])
     prf.add_item(4,
                  "rewrite_goal",
                  args=("plus_def_2", eq(plus(S(n), zero), S(n))),
                  prevs=[3])
     prf.add_item(5, "implies_intr", args=eq(plus(n, zero), n), prevs=[4])
     prf.add_item(6, "forall_intr", args=n, prevs=[5])
     prf.add_item(7,
                  "apply_theorem_for",
                  args=("nat_induct", {}, {
                      "P": Term.mk_abs(n, eq(plus(n, zero), n)),
                      "x": n
                  }),
                  prevs=[1, 6])
     th = Thm.mk_equals(plus(n, zero), n)
     self.assertEqual(thy.check_proof(prf), th)
Example #25
0
    def testIntro(self):
        basic.load_theory('logic_base')
        macro = logic.intros_macro()

        Ta = TVar('a')
        x = Var('x', Ta)
        P = Var('P', TFun(Ta, BoolType))
        C = Var('C', BoolType)
        ex_P = Exists(x, P(x))
        pt1 = ProofTerm.assume(ex_P)
        pt2 = ProofTerm.variable('x', Ta)
        pt3 = ProofTerm.assume(P(x))
        pt4 = ProofTerm.sorry(Thm([P(x)], C))
        pt4 = ProofTerm('intros', args=[ex_P], prevs=[pt1, pt2, pt3, pt4])
        prf = pt4.export()
        self.assertEqual(theory.check_proof(prf), Thm([ex_P], C))
Example #26
0
    def testAllConj(self):
        """Proof of (!x. A x & B x) --> (!x. A x) & (!x. B x)."""
        thy = basic.load_theory('logic_base')
        Ta = TVar("a")
        A = Var("A", TFun(Ta, boolT))
        B = Var("B", TFun(Ta, boolT))
        x = Var("x", Ta)
        all_conj = Term.mk_all(x, logic.mk_conj(A(x), B(x)))
        all_A = Term.mk_all(x, A(x))
        all_B = Term.mk_all(x, B(x))
        conj_all = logic.mk_conj(all_A, all_B)

        prf = Proof(all_conj)
        prf.add_item(1, "forall_elim", args=x, prevs=[0])
        prf.add_item(2, "theorem", args="conjD1")
        prf.add_item(3, "substitution", args={"A": A(x), "B": B(x)}, prevs=[2])
        prf.add_item(4, "implies_elim", prevs=[3, 1])
        prf.add_item(5, "forall_intr", args=x, prevs=[4])
        prf.add_item(6, "theorem", args="conjD2")
        prf.add_item(7, "substitution", args={"A": A(x), "B": B(x)}, prevs=[6])
        prf.add_item(8, "implies_elim", prevs=[7, 1])
        prf.add_item(9, "forall_intr", args=x, prevs=[8])
        prf.add_item(10, "theorem", args="conjI")
        prf.add_item(11,
                     "substitution",
                     args={
                         "A": all_A,
                         "B": all_B
                     },
                     prevs=[10])
        prf.add_item(12, "implies_elim", prevs=[11, 5])
        prf.add_item(13, "implies_elim", prevs=[12, 9])
        prf.add_item(14, "implies_intr", args=all_conj, prevs=[13])
        th = Thm.mk_implies(all_conj, conj_all)
        self.assertEqual(thy.check_proof(prf), th)
Example #27
0
def load_system(filename):
    dn = os.path.dirname(os.path.realpath(__file__))
    with open(os.path.join(dn, 'examples/' + filename + '.json'),
              encoding='utf-8') as a:
        data = json.load(a)

    basic.load_theory('gcl')

    name = data['name']
    vars = []
    for nm, str_T in data['vars'].items():
        T = parser.parse_type(str_T)
        vars.append(Var(nm, T))

    for i, nm in enumerate(data['states']):
        theory.thy.add_term_sig(nm, NatType)
        theory.thy.add_theorem(nm + "_def",
                               Thm([], Eq(Const(nm, NatType), Nat(i))))

    states = [Const(nm, NatType) for nm in data['states']]

    rules = []
    for rule in data['rules']:
        if isinstance(rule['var'], str):
            rule_var = Var(rule['var'], NatType)
            cur_vars = {v.name: v.T for v in vars + [rule_var]}
        else:
            assert isinstance(rule['var'], list)
            rule_var = [Var(nm, NatType) for nm in rule['var']]
            cur_vars = {v.name: v.T for v in vars + rule_var}

        with context.fresh_context(vars=cur_vars):
            guard = parser.parse_term(rule['guard'])
            assign = dict()
            for k, v in rule['assign'].items():
                assign[parser.parse_term(k)] = parser.parse_term(v)
            rules.append((rule_var, guard, assign))

    invs = []
    for inv in data['invs']:
        inv_vars = [Var(nm, NatType) for nm in inv['vars']]
        with context.fresh_context(vars={v.name: v.T
                                         for v in vars + inv_vars}):
            prop = parser.parse_term(inv['prop'])
        invs.append((inv_vars, prop))

    return ParaSystem(name, vars, states, rules, invs)
Example #28
0
def process_file(input):
    basic.load_theory('hoare')

    dn = os.path.dirname(os.path.realpath(__file__))
    with open(os.path.join(dn, 'examples/' + input + '.json'),
              encoding='utf-8') as a:
        data = json.load(a)

    content = data['content']

    for run in content:
        if run['ty'] == 'vcg':
            c = com_parser.parse(run['com'])
            pre = cond_parser.parse(run['pre'])
            post = cond_parser.parse(run['post'])
            c.pre = [pre]
            c.compute_wp(post)
Example #29
0
    def testPrintFunction(self):
        f = Var("f", TFun(Ta, Ta))
        Tb = TVar('b')
        Tc = TVar('c')
        g = Var('g', TFun(Tb, Tc))
        h = Var('h', TFun(Ta, Tb))
        test_data = [
            (function.mk_fun_upd(f, a, b), "(f)(a := b)"),
            (function.mk_fun_upd(f, a, b, b, a), "(f)(a := b, b := a)"),
            (function.mk_comp(g, h), "g O h"),
            (function.mk_comp(g, h)(a), "(g O h) a"),
            (function.mk_const_fun(NatType, nat.zero), "%x::nat. (0::nat)"),
        ]

        basic.load_theory('function')
        with global_setting(unicode=False):
            for t, s in test_data:
                self.assertEqual(printer.print_term(t), s)
Example #30
0
    def testPrintFunction(self):
        test_data = [
            (function.mk_fun_upd(f, a, b), "(f)(a := b)"),
            (function.mk_fun_upd(f, a, b, b, a), "(f)(a := b, b := a)"),
        ]

        thy = basic.load_theory('function')
        for t, s in test_data:
            self.assertEqual(printer.print_term(thy, t), s)