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 testPrintTheoryExtension2(self): thy_ext = TheoryExtension() thy_ext.add_extension(AxType("nat", 0)) thy_ext.add_extension(AxConstant("id", TFun(Ta, Ta))) str_thy_ext = "\n".join(["AxType nat 0", "AxConstant id :: 'a => 'a"]) self.assertEqual(str(thy_ext), str_thy_ext)
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 testInductNat(self): nat = Type("nat") nat_ext = induct.add_induct_type( "nat", [], [("zero", nat, []), ("Suc", TFun(nat, nat), ["n"])]) zero = Const("zero", nat) S = Const("Suc", TFun(nat, nat)) n = Var("n", nat) n2 = Var("n'", nat) x = Var("x", nat) P = Var("P", TFun(nat, boolT)) res = [ AxType("nat", 0), AxConstant("zero", nat), AxConstant("Suc", TFun(nat, nat)), Theorem("nat_zero_Suc_neq", Thm([], logic.neg(eq(zero, S(n))))), Theorem("nat_Suc_inject", Thm([], imp(eq(S(n), S(n2)), eq(n, n2)))), Theorem("nat_induct", Thm([], imp(P(zero), all(n, imp(P(n), P(S(n)))), P(x)))), Attribute("nat_induct", "var_induct") ] self.assertEqual(nat_ext.data, res)
def add_induct_predicate(name, T, props): """Add the given inductive predicate. The inductive predicate is specified by the name and type of the predicate, and a list of introduction rules, where each introduction rule must be given a name. """ exts = TheoryExtension() exts.add_extension(AxConstant(name, T)) for th_name, prop in props: exts.add_extension(Theorem(th_name, Thm([], prop))) exts.add_extension(Attribute(th_name, "hint_backward")) # Case rule Targs, _ = T.strip_type() vars = [] for i, Targ in enumerate(Targs): vars.append(Var("_a" + str(i + 1), Targ)) P = Var("P", boolT) pred = Const(name, T) assum0 = pred(*vars) assums = [] for th_name, prop in props: As, C = prop.strip_implies() assert C.head == pred, "add_induct_predicate: wrong form of prop." eq_assums = [ Term.mk_equals(var, arg) for var, arg in zip(vars, C.args) ] assum = Term.mk_implies(*(eq_assums + As), P) prop_vars = term.get_vars(prop) for var in reversed(term.get_vars(prop)): assum = Term.mk_all(var, assum) assums.append(assum) prop = Term.mk_implies(*([assum0] + assums + [P])) exts.add_extension(Theorem(name + "_cases", Thm([], prop))) return exts
def testInductAdd(self): nat = Type("nat") plus = Const("plus", TFun(nat, nat, nat)) zero = Const("zero", nat) S = Const("Suc", TFun(nat, nat)) m = Var("m", nat) n = Var("n", nat) ext = induct.add_induct_def( 'plus', TFun(nat, nat, nat), [ eq(plus(zero, n), n), eq(plus(S(m), n), S(plus(m, n)))]) res = [ AxConstant("plus", TFun(nat, nat, nat)), Theorem("plus_def_1", Thm([], eq(plus(zero, n), n))), Attribute("plus_def_1", "hint_rewrite"), Theorem("plus_def_2", Thm([], eq(plus(S(m), n), S(plus(m, n))))), Attribute("plus_def_2", "hint_rewrite"), ] self.assertEqual(ext.data, res)
def testInductPredicate(self): nat = Type("nat") even = Const("even", TFun(nat, boolT)) zero = Const("zero", nat) Suc = Const("Suc", TFun(nat, nat)) n = Var("n", nat) prop_zero = even(zero) prop_Suc = Term.mk_implies(even(n), even(Suc(Suc(n)))) data = [("even_zero", prop_zero), ("even_Suc", prop_Suc)] even_ext = induct.add_induct_predicate("even", TFun(nat, boolT), data) a1 = Var("_a1", nat) P = Var("P", boolT) res = [ AxConstant("even", TFun(nat, boolT)), Theorem("even_zero", Thm([], even(zero))), Attribute("even_zero", "hint_backward"), Theorem("even_Suc", Thm.mk_implies(even(n), even(Suc(Suc(n))))), Attribute("even_Suc", "hint_backward"), Theorem("even_cases", Thm.mk_implies(even(a1), imp(eq(a1,zero), P), all(n, imp(eq(a1,Suc(Suc(n))), even(n), P)), P)) ] self.assertEqual(even_ext.data, res)
def testInductProd(self): Ta = TVar("a") Tb = TVar("b") Tab = Type("prod", Ta, Tb) prod_ext = induct.add_induct_type( "prod", ["a", "b"], [("Pair", TFun(Ta, Tb, Tab), ["a", "b"])]) a = Var("a", Ta) b = Var("b", Tb) a2 = Var("a'", Ta) b2 = Var("b'", Tb) pair = Const("Pair", TFun(Ta, Tb, Tab)) P = Var("P", TFun(Tab, boolT)) x = Var("x", Tab) res = [ AxType("prod", 2), AxConstant("Pair", TFun(Ta, Tb, Tab)), Theorem("prod_Pair_inject", Thm([], imp(eq(pair(a, b), pair(a2, b2)), conj(eq(a, a2), eq(b, b2))))), Theorem("prod_induct", Thm([], imp(all(a, all(b, P(pair(a, b)))), P(x)))), Attribute("prod_induct", "var_induct") ] self.assertEqual(prod_ext.data, res)
def add_induct_def(name, T, eqs): """Add the given inductive definition. The inductive definition is specified by the name and type of the constant, and a list of equations. For example, addition on natural numbers is specified by: ('plus', nat => nat => nat, [(plus(0,n) = n, plus(Suc(m), n) = Suc(plus(m, n)))]). Multiplication on natural numbers is specified by: ('times', nat => nat => nat, [(times(0,n) = 0, times(Suc(m), n) = plus(n, times(m,n)))]). """ exts = TheoryExtension() exts.add_extension(AxConstant(name, T)) for i, prop in enumerate(eqs): th_name = name + "_def_" + str(i + 1) exts.add_extension(Theorem(th_name, Thm([], prop))) exts.add_extension(Attribute(th_name, "hint_rewrite")) return exts
def add_induct_type(name, targs, constrs): """Add the given inductive type to the theory. The inductive type is specified by name, arity (as list of default names of type arguments), and a list of constructors (triple consisting of name of the constant, type of the constant, and a list of suggested names of the arguments). For example, the natural numbers is specified by: (nat, [], [(0, nat, []), (Suc, nat => nat, ["n"])]). List type is specified by: (list, ["a"], [(nil, 'a list, []), (cons, 'a => 'a list => 'a list, ["x", "xs"])]). """ exts = TheoryExtension() # Add to type and term signature. exts.add_extension(AxType(name, len(targs))) for cname, cT, _ in constrs: exts.add_extension(AxConstant(cname, cT)) # Add non-equality theorems. for (cname1, cT1, vars1), (cname2, cT2, vars2) in itertools.combinations(constrs, 2): # For each A x_1 ... x_m and B y_1 ... y_n, get the theorem # ~ A x_1 ... x_m = B y_1 ... y_n. argT1, _ = cT1.strip_type() argT2, _ = cT2.strip_type() lhs_vars = [Var(nm, T) for nm, T in zip(vars1, argT1)] rhs_vars = [Var(nm, T) for nm, T in zip(vars2, argT2)] A = Const(cname1, cT1) B = Const(cname2, cT2) lhs = A(*lhs_vars) rhs = B(*rhs_vars) neq = logic.neg(Term.mk_equals(lhs, rhs)) th_name = name + "_" + cname1 + "_" + cname2 + "_neq" exts.add_extension(Theorem(th_name, Thm([], neq))) # Add injectivity theorems. for cname, cT, vars in constrs: # For each A x_1 ... x_m with m > 0, get the theorem # A x_1 ... x_m = A x_1' ... x_m' --> x_1 = x_1' & ... & x_m = x_m' if vars: argT, _ = cT.strip_type() lhs_vars = [Var(nm, T) for nm, T in zip(vars, argT)] rhs_vars = [Var(nm + "'", T) for nm, T in zip(vars, argT)] A = Const(cname, cT) assum = Term.mk_equals(A(*lhs_vars), A(*rhs_vars)) concls = [ Term.mk_equals(var1, var2) for var1, var2 in zip(lhs_vars, rhs_vars) ] concl = logic.mk_conj(*concls) if len(concls) > 1 else concls[0] th_name = name + "_" + cname + "_inject" exts.add_extension(Theorem(th_name, Thm.mk_implies(assum, concl))) # Add the inductive theorem. tvars = [TVar(targ) for targ in targs] T = Type(name, *tvars) var_P = Var("P", TFun(T, boolT)) ind_assums = [] for cname, cT, vars in constrs: A = Const(cname, cT) argT, _ = cT.strip_type() args = [Var(nm, T2) for nm, T2 in zip(vars, argT)] C = var_P(A(*args)) As = [var_P(Var(nm, T2)) for nm, T2 in zip(vars, argT) if T2 == T] ind_assum = Term.mk_implies(*(As + [C])) for arg in reversed(args): ind_assum = Term.mk_all(arg, ind_assum) ind_assums.append(ind_assum) ind_concl = var_P(Var("x", T)) th_name = name + "_induct" exts.add_extension( Theorem(th_name, Thm.mk_implies(*(ind_assums + [ind_concl])))) exts.add_extension(Attribute(th_name, "var_induct")) return exts