def testInductList(self): Ta = TVar("a") Tlista = Type("list", Ta) list_ext = induct.add_induct_type( "list", ["a"], [("nil", Tlista, []), ("cons", TFun(Ta, Tlista, Tlista), ["x", "xs"])]) nil = Const("nil", Tlista) cons = Const("cons", TFun(Ta, Tlista, Tlista)) x = Var("x", Ta) xs = Var("xs", Tlista) x2 = Var("x'", Ta) xs2 = Var("xs'", Tlista) P = Var("P", TFun(Tlista, boolT)) xlist = Var("x", Tlista) res = [ AxType("list", 1), AxConstant("nil", Tlista), AxConstant("cons", TFun(Ta, Tlista, Tlista)), Theorem("list_nil_cons_neq", Thm([], logic.neg(eq(nil, cons(x, xs))))), Theorem("list_cons_inject", Thm([], imp(eq(cons(x, xs), cons(x2, xs2)), conj(eq(x, x2), eq(xs, xs2))))), Theorem("list_induct", Thm([], imp(P(nil), all(x, all(xs, imp(P(xs), P(cons(x, xs))))), P(xlist)))), Attribute("list_induct", "var_induct") ] self.assertEqual(list_ext.data, res)
def get_proof(self): invC = Const("inv", TFun(gcl.stateT, boolT)) transC = Const("trans", TFun(gcl.stateT, gcl.stateT, boolT)) s1 = Var("s1", gcl.stateT) s2 = Var("s2", gcl.stateT) prop = Thm.mk_implies(invC(s1), transC(s1, s2), invC(s2)) # print(printer.print_thm(self.thy, prop)) trans_pt = ProofTerm.assume(transC(s1, s2)) # print(printer.print_thm(self.thy, trans_pt.th)) P = Term.mk_implies(invC(s1), invC(s2)) ind_pt = apply_theorem(self.thy, "trans_cases", inst={ "a1": s1, "a2": s2, "P": P }) # print(printer.print_thm(self.thy, ind_pt.th)) ind_As, ind_C = ind_pt.prop.strip_implies() for ind_A in ind_As[1:-1]: # print("ind_A: ", printer.print_term(self.thy, ind_A)) vars, As, C = logic.strip_all_implies(ind_A, ["s", "k"]) # for A in As: # print("A: ", printer.print_term(self.thy, A)) # print("C: ", printer.print_term(self.thy, C)) eq1 = ProofTerm.assume(As[0]) eq2 = ProofTerm.assume(As[1]) guard = ProofTerm.assume(As[2]) inv_pre = ProofTerm.assume(As[3]).on_arg(self.thy, rewr_conv(eq1)) \ .on_prop(self.thy, rewr_conv("inv_def")) C_goal = ProofTerm.assume(C).on_arg(self.thy, rewr_conv(eq2)) \ .on_prop(self.thy, rewr_conv("inv_def"))
def mk_exists(x, body): """Given a variable x and a term t possibly depending on x, return the term ?x. t. """ exists_t = Const("exists", TFun(TFun(x.T, boolT), boolT)) return exists_t(Term.mk_abs(x, body))
def get_proof(self): invC = Const("inv", TFun(gcl.stateT, BoolType)) transC = Const("trans", TFun(gcl.stateT, gcl.stateT, BoolType)) s1 = Var("s1", gcl.stateT) s2 = Var("s2", gcl.stateT) prop = Thm([], Implies(invC(s1), transC(s1, s2), invC(s2))) # print(printer.print_thm(prop)) trans_pt = ProofTerm.assume(transC(s1, s2)) # print(printer.print_thm(trans_pt.th)) P = Implies(invC(s1), invC(s2)) ind_pt = apply_theorem("trans_cases", inst=Inst(a1=s1, a2=s2, P=P)) # print(printer.print_thm(ind_pt.th)) ind_As, ind_C = ind_pt.prop.strip_implies() for ind_A in ind_As[1:-1]: # print("ind_A: ", ind_A) vars, As, C = logic.strip_all_implies(ind_A, ["s", "k"]) # for A in As: # print("A: ", A) # print("C: ", C) eq1 = ProofTerm.assume(As[0]) eq2 = ProofTerm.assume(As[1]) guard = ProofTerm.assume(As[2]) inv_pre = ProofTerm.assume(As[3]).on_arg(rewr_conv(eq1)).on_prop( rewr_conv("inv_def")) C_goal = ProofTerm.assume(C).on_arg(rewr_conv(eq2)).on_prop( rewr_conv("inv_def"))
def testFirstOrderMatchFun(self): """First-order matching of variables in function position.""" P = Var("P", TFun(Ta, boolT)) Q = Var("Q", TFun(Ta, boolT)) C = Const("C", TFun(boolT, boolT, boolT)) test_data = [ (abs(x, P(x)), abs(x, C(P(x), Q(x))), { "P": abs(x, C(P(x), Q(x))) }), (abs(x, C(P(x), Q(x))), abs(x, C(Q(x), P(x))), { "P": Q, "Q": P }), (abs(x, C(P(x), P(x))), abs(x, C(C(P(x), Q(x)), C(P(x), Q(x)))), { "P": abs(x, C(P(x), Q(x))) }), (exists(x, P(x)), exists(x, conj(P(x), Q(x))), { "P": abs(x, conj(P(x), Q(x))) }), ] for pat, t, inst in test_data: if inst is not None: self.assertEqual(matcher.first_order_match(pat, t)[1], inst) else: self.assertRaises(matcher.MatchException, matcher.first_order_match, pat, t)
def testPrintType(self): test_data = [ (Ta, "'a"), (TVar("ab"), "'ab"), (TConst("bool"), "bool"), (TConst("list", Ta), "'a list"), (TConst("list", TConst("list", Ta)), "'a list list"), (TConst("tree", Ta, Tb), "('a, 'b) tree"), (TFun(Ta, Tb), "'a => 'b"), (TFun(Ta, Tb, Tc), "'a => 'b => 'c"), (TFun(TFun(Ta, Tb), Tc), "('a => 'b) => 'c"), (TFun(TConst("list", Ta), Tb), "'a list => 'b"), (TFun(Ta, TConst("list", Tb)), "'a => 'b list"), (TConst("list", TFun(Ta, Tb)), "('a => 'b) list"), (TConst("list", TConst("list", TFun(Ta, Tb))), "('a => 'b) list list"), (TFun(TConst("list", Ta), TConst("list", Tb)), "'a list => 'b list"), (TConst("list", TFun(TConst("list", Ta), Tb)), "('a list => 'b) list"), ] for T, str_T in test_data: with global_setting(unicode=False): self.assertEqual(str(T), str_T)
def testInferType(self): test_data = [ # A1 --> A2 (Const("implies", None)(Var("A1", None), Var("A2", None)), Term.mk_implies(Var("A1", boolT), Var("A2", boolT))), # A1 = A2 (Const("equals", None)(Var("A1", boolT), Var("A2", None)), Term.mk_equals(Var("A1", boolT), Var("A2", boolT))), # a = b (Const("equals", None)(Var("a", None), Var("b", None)), Const("equals", TFun(Ta, Ta, boolT))(Var("a", Ta), Var("b", Ta))), # %x. P x (Abs("x", None, Var("P", None)(Bound(0))), Abs("x", Ta, Var("P", TFun(Ta, boolT))(Bound(0)))), # %x y. x = y (Abs("x", Ta, Abs("y", None, Const("equals", None)(Bound(1), Bound(0)))), Abs( "x", Ta, Abs("y", Ta, Const("equals", TFun(Ta, Ta, boolT))(Bound(1), Bound(0))))), # [a] (Const("cons", None)(Var("a", None), Const("nil", None)), list.cons(Ta)(Var("a", Ta), Const("nil", listT(Ta)))), ] for t, res in test_data: self.assertEqual(type_infer(thy, ctxt, t), res)
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)
def testMatchFail(self): test_data = [ (TFun(Ta, Ta), TFun(Ta, Tb)), (boolT, Ta), ] for pat, T in test_data: self.assertRaises(TypeMatchException, pat.match, T)
def mk_some(x, body): """Given a variable x and a term P possibly depending on x, return the term SOME x. P. """ assert x.is_var(), "mk_some" some_t = Const("Some", TFun(TFun(x.T, BoolType), x.T)) return some_t(Lambda(x, body))
def mk_exists1(x, body): """Given a variable x and a term P possibly depending on x, return the term ?!x. P. """ assert x.is_var(), "mk_exists1" exists1_t = Const("exists1", TFun(TFun(x.T, BoolType), BoolType)) return exists1_t(Lambda(x, body))
def mk_all(x, body): """Given a variable x and a term t possibly depending on x, return the term !x. t. Optional arguments var_name and T specify the suggested name and type of the bound variable. """ all_t = Const("all", TFun(TFun(x.T, boolT), boolT)) return all_t(Term.mk_abs(x, body))
def testStripType(self): test_data = [ (Ta, ([], Ta)), (TFun(Ta, Tb), ([Ta], Tb)), (TFun(Ta, Ta, Tb), ([Ta, Ta], Tb)), ] for T, res in test_data: self.assertEqual(T.strip_type(), res)
def testGetTSubs(self): test_data = [ (boolT, [boolT]), (TFun(Ta, Ta), [TFun(Ta, Ta), Ta]), (TFun(Ta, Tb), [TFun(Ta, Tb), Ta, Tb]), ] for T, res in test_data: self.assertEqual(T.get_tsubs(), res)
def testGetTVars(self): test_data = [ (boolT, []), (TFun(Ta, Ta), [Ta]), (TFun(Ta, Tb), [Ta, Tb]), ] for T, res in test_data: self.assertEqual(T.get_tvars(), res)
def testGetTSubs(self): test_data = [ (BoolType, [BoolType]), (TFun(Ta, Ta), [Ta, TFun(Ta, Ta)]), (TFun(Ta, Tb), [Ta, Tb, TFun(Ta, Tb)]), ] for T, res in test_data: self.assertEqual(T.get_tsubs(), res)
def testIsPattern(self): test_data = [ (Var('a', Ta), True), (Var('f', TFun(Ta, Tb))(Var('a', Ta)), False), (Const('f', TFun(Ta, Tb))(Var('a', Ta)), True), ] for t, res in test_data: self.assertEqual(matcher.is_pattern(t, []), res)
def testCheckedExtend3(self): """Axiomatized constant.""" exts = [ extension.TConst("nat", 0), extension.Constant("id", TFun(Ta,Ta)) ] ext_report = theory.thy.checked_extend(exts) self.assertEqual(theory.thy.get_type_sig("nat"), 0) self.assertEqual(theory.thy.get_term_sig("id"), TFun(Ta,Ta))
def testIntros(self): Ta = TVar('a') x = Var('x', Ta) P = Var('P', TFun(Ta, boolT)) Q = Var('Q', TFun(Ta, boolT)) goal = Thm([], Term.mk_all(x, Term.mk_implies(P(x), Q(x)))) intros_tac = tactic.intros() pt = intros_tac.get_proof_term(thy, ProofTerm.sorry(goal), args=['x']) prf = pt.export() self.assertEqual(thy.check_proof(prf), goal)
def testIntroduction3(self): Ta = TVar("a") A = Var("A", TFun(Ta, boolT)) B = Var("B", TFun(Ta, boolT)) x = Var("x", Ta) state = ProofState.init_state(thy, [A, B], [], Term.mk_all(x, imp(A(x), B(x)))) state.introduction(0, ["x"]) self.assertEqual(state.check_proof(), Thm([], Term.mk_all(x, imp(A(x), B(x))))) self.assertEqual(len(state.prf.items), 1) self.assertEqual(len(state.prf.items[0].subproof.items), 4)
def testSubst(self): test_data = [ (STa, Tb), (STb, Ta), (TFun(STa, Tb), TFun(Tb, Tb)), (TFun(STa, STb), TFun(Tb, Ta)), (TConst("list", STa), TConst("list", Tb)), ] for T, res in test_data: self.assertEqual(T.subst(TyInst(a=Tb, b=Ta)), res)
def testCheckedExtend3(self): """Axiomatized constant.""" thy = Theory.EmptyTheory() thy_ext = TheoryExtension() thy_ext.add_extension(AxType("nat", 0)) thy_ext.add_extension(AxConstant("id", TFun(Ta,Ta))) ext_report = thy.checked_extend(thy_ext) self.assertEqual(thy.get_type_sig("nat"), 0) self.assertEqual(thy.get_term_sig("id"), TFun(Ta,Ta)) self.assertEqual(ext_report.get_axioms(), [("nat", 0), ("id", TFun(Ta,Ta))])
def infer(t, bd_vars): # Var case: if type is not known, try to obtain it from context, # otherwise, make a new type. if t.is_var(): if t.T is None: if t.name in ctxt: t.T = ctxt[t.name] else: t.T = new_type() add_type(t.T) return t.T # Const case: if type is not known, obtain it from theory, # replacing arbitrary variables by new types. elif t.is_const(): if t.T is None: T = thy.get_term_sig(t.name) Tvars = T.get_tvars() tyinst = dict() for Tv in Tvars: tyinst[Tv.name] = new_type() t.T = T.subst(tyinst) add_type(t.T) return t.T # Comb case: recursively infer type of fun and arg, then # unify funT with argT => resT, where resT is a new type. elif t.is_comb(): funT = infer(t.fun, bd_vars) argT = infer(t.arg, bd_vars) resT = new_type() add_type(TFun(argT, resT)) unify(uf, funT, TFun(argT, resT)) return resT # Abs case: if var_T is not known, make a new type. Recursively # call infer on the body under the context where var_name has # type var_T. The resulting type is var_T => body_T. elif t.is_abs(): if t.var_T is None: t.var_T = new_type() add_type(t.var_T) bodyT = infer(t.body, [t.var_T] + bd_vars) resT = TFun(t.var_T, bodyT) add_type(resT) return resT # Bound variables should not appear during inference. elif t.is_bound(): return bd_vars[t.n] else: raise TypeError()
def run_test(self, data, verbose=False): Ta = TVar('a') context.set_context('nat', vars={ 'a': Ta, 'b': Ta, 'c': Ta, 'd': Ta, 'f': TFun(Ta, Ta), 'g': TFun(Ta, Ta), 'R': TFun(Ta, Ta, Ta), 'm': NatType, 'n': NatType, 'p': NatType, 'q': NatType, 'x': NatType, 'y': NatType, 'z': NatType }) closure = congc.CongClosureHOL() for item in data: if item[0] == MERGE: _, s, t = item s = parser.parse_term(s) t = parser.parse_term(t) closure.merge(s, t) if verbose: print("Merge %s, %s\nAfter\n%s" % (s, t, closure)) elif item[0] == CHECK: _, s, t, b = item s = parser.parse_term(s) t = parser.parse_term(t) self.assertEqual(closure.test(s, t), b) elif item[0] == EXPLAIN: _, s, t = item s = parser.parse_term(s) t = parser.parse_term(t) prf = closure.explain(s, t).export() self.assertEqual(theory.check_proof(prf), Thm([], Eq(s, t))) if verbose: print("Proof of %s" % Eq(s, t)) print(prf) elif item[0] == MATCH: _, pat, t, res = item pat = parser.parse_term(pat) t = parser.parse_term(t) for res_inst in res: for k in res_inst: res_inst[k] = parser.parse_term(res_inst[k]) inst = closure.ematch(pat, t) self.assertEqual(inst, res) else: raise NotImplementedError
def testCheckTermFail(self): test_data = [ Const("random", Ta), Const("equals", TFun(Ta, Tb, BoolType)), Const("equals", TFun(Ta, Ta, Tb)), Const("implies", TFun(Ta, Ta, BoolType)), Comb(Const("random", Tab), x), f(Const("random", Ta)), Abs("x", Ta, Const("random", Ta)), ] for t in test_data: self.assertRaises(TheoryException, theory.thy.check_term, t)
def add_invariant(self): """Add the invariant for the system in GCL.""" s = Var("s", gcl.stateT) invC = Const("inv", TFun(gcl.stateT, BoolType)) inv_rhs = And( *[gcl.convert_term(self.var_map, s, t) for _, t in self.invs]) prop = Eq(invC(s), inv_rhs) exts = [ extension.Constant("inv", TFun(gcl.stateT, BoolType)), extension.Theorem("inv_def", Thm([], prop)) ] theory.thy.unchecked_extend(exts)
def add_invariant(self): """Add the invariant for the system in GCL.""" s = Var("s", gcl.stateT) invC = Const("inv", TFun(gcl.stateT, boolT)) inv_rhs = logic.mk_conj( *[gcl.convert_term(self.var_map, s, t) for _, t in self.invs]) prop = Term.mk_equals(invC(s), inv_rhs) exts = extension.TheoryExtension() exts.add_extension(extension.AxConstant("inv", TFun(gcl.stateT, boolT))) exts.add_extension(extension.Theorem("inv_def", Thm([], prop))) self.thy.unchecked_extend(exts)
def convert(t): """Convert term t to Z3 input.""" if t.is_var(): T = t.get_type() if T == nat.natT: return z3.Int(t.name) elif T == TFun(nat.natT, nat.natT): return z3.Function(t.name, z3.IntSort(), z3.IntSort()) elif T == TFun(nat.natT, boolT): return z3.Function(t.name, z3.IntSort(), z3.BoolSort()) elif T == boolT: return z3.Bool(t.name) else: print("convert: unsupported type " + repr(T)) raise NotImplementedError elif t.is_all(): if t.arg.var_T == nat.natT: v = Var(t.arg.var_name, nat.natT) z3_v = z3.Int(t.arg.var_name) return z3.ForAll([z3_v], convert(t.arg.subst_bound(v))) else: raise NotImplementedError elif t.is_implies(): return z3.Implies(convert(t.arg1), convert(t.arg)) elif t.is_equals(): return convert(t.arg1) == convert(t.arg) elif logic.is_conj(t): return z3.And(convert(t.arg1), convert(t.arg)) elif logic.is_disj(t): return z3.Or(convert(t.arg1), convert(t.arg)) elif logic.is_neg(t): return z3.Not(convert(t.arg)) elif nat.is_plus(t): return convert(t.arg1) + convert(t.arg) elif nat.is_times(t): return convert(t.arg1) * convert(t.arg) elif nat.is_binary(t): return nat.from_binary(t) elif t.is_comb(): return convert(t.fun)(convert(t.arg)) elif t.is_const(): if t == logic.true: return z3.BoolVal(True) elif t == logic.false: return z3.BoolVal(False) else: print("convert: unsupported constant " + repr(t)) raise NotImplementedError else: print("convert: unsupported operation " + repr(t)) raise NotImplementedError
def testPrintRename(self): test_data = [ (Const("exists", TFun(TFun(NatType, BoolType), BoolType))(Abs("x", NatType, nat.less(Bound(0), Var("x", NatType)))), "?x1. x1 < x"), (Abs("x", NatType, nat.less(Bound(0), Var("x", NatType))), "%x1. x1 < x"), ] with global_setting(unicode=False): for t, s in test_data: self.assertEqual(printer.print_term(t), s)
def testCheckTypeFail(self): test_data = [ TConst("bool", Ta), TConst("bool", Ta, Ta), TConst("fun"), TConst("fun", Ta), TConst("fun", Ta, Ta, Ta), TFun(TConst("bool", Ta), TConst("bool")), TFun(TConst("bool"), TConst("bool", Ta)), TConst("random") ] for T in test_data: self.assertRaises(TheoryException, theory.thy.check_type, T)