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_term(self, thy, goal, *, args=None, prevs=None): assert isinstance(args, Term), "cases" As = goal.hyps C = goal.prop goal1 = ProofTerm.sorry(Thm(goal.hyps, Term.mk_implies(args, C))) goal2 = ProofTerm.sorry( Thm(goal.hyps, Term.mk_implies(logic.neg(args), C))) return apply_theorem(thy, 'classical_cases', goal1, goal2)
def testEvalSem5(self): com = While(abs(s, logic.neg(eq(s(zero), nat.to_binary(3)))), assn_true, incr_one) st = mk_const_fun(natT, zero) st2 = fun_upd_of_seq(0, 3) goal = Sem(com, st, st2) prf = hoare.eval_Sem_macro().get_proof_term(thy, goal, []).export() rpt = ProofReport() self.assertEqual(thy.check_proof(prf, rpt), Thm([], goal))
def testPelletier(self): with open('prover/tests/pelletier.json', 'r', encoding='utf-8') as f: f_data = json.load(f) for problem in f_data: ctxt = parser.parse_vars(thy, problem['vars']) prop = parser.parse_term(thy, ctxt, problem['prop']) cnf, _ = encode.encode(logic.neg(prop)) self.assertIsNone(sat.solve_cnf(cnf))
def testEvalSem4(self): com = Cond(abs(s, logic.neg(eq(s(zero), one))), incr_one, Skip) st = mk_const_fun(natT, zero) st2 = fun_upd_of_seq(0, 1) goal = Sem(com, st, st2) prf = hoare.eval_Sem_macro().get_proof_term(thy, goal, []).export() self.assertEqual(thy.check_proof(prf), Thm([], goal)) goal = Sem(com, st2, st2) prf = hoare.eval_Sem_macro().get_proof_term(thy, goal, []).export() self.assertEqual(thy.check_proof(prf), Thm([], goal))
def testNatIneqMacro(self): test_data = [ (0, 1), (1, 0), (0, 2), (2, 0), (1, 2), (2, 1), (1, 3), (3, 1), (2, 3), (3, 2), (10, 13), (17, 19), (22, 24), ] macro = nat.nat_const_ineq_macro() for m, n in test_data: goal = logic.neg(Term.mk_equals(nat.to_binary(m), nat.to_binary(n))) prf = macro.get_proof_term(thy, goal, []).export() self.assertEqual(thy.check_proof(prf), Thm([], goal))
def convert(t): if t.head in var_map: if len(t.args) == 0: return s(Ident(to_binary(var_map[t.head]))) elif len(t.args) == 1: return s(Para(Ident(to_binary(var_map[t.head])), t.arg)) else: raise NotImplementedError elif t.is_equals(): return Term.mk_equals(convert(t.arg1), convert(t.arg)) elif logic.is_neg(t): return logic.neg(convert(t.arg)) elif logic.is_conj(t): return logic.conj(convert(t.arg1), convert(t.arg)) elif logic.is_disj(t): return logic.disj(convert(t.arg1), convert(t.arg)) elif t.get_type() == boolT: return BoolV(t) elif t.get_type() == natT: return NatV(t) else: raise NotImplementedError
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_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
def neg(self, t): return logic.neg(t)
def encode(t): """Convert a holpy term into an equisatisfiable CNF. The result is a pair (cnf, prop), where cnf is the CNF form, and prop is a theorem stating that t, together with equality assumptions, imply the statement in CNF. """ # Find the list of logical subterms, remove duplicates. subterms = logic_subterms(t) subterms = list(OrderedDict.fromkeys(subterms)) subterms_dict = dict() for i, st in enumerate(subterms): subterms_dict[st] = i # The subterm at index i corresponds to variable x(i+1). def get_var(i): return Var("x" + str(i + 1), boolT) # Obtain the results: # eqs -- list of equality assumptions # clauses -- list of clauses eqs = [] clauses = [] for i, st in enumerate(subterms): l = get_var(i) if st.is_implies() or st.is_equals() or logic.is_conj( st) or logic.is_disj(st): r1 = get_var(subterms_dict[st.arg1]) r2 = get_var(subterms_dict[st.arg]) f = st.head eqs.append(Term.mk_equals(l, f(r1, r2))) if st.is_implies(): clauses.extend(encode_eq_imp(l, r1, r2)) elif st.is_equals(): clauses.extend(encode_eq_eq(l, r1, r2)) elif logic.is_conj(st): clauses.extend(encode_eq_conj(l, r1, r2)) else: # st.is_disj() clauses.extend(encode_eq_disj(l, r1, r2)) elif logic.is_neg(st): r = get_var(subterms_dict[st.arg]) eqs.append(Term.mk_equals(l, logic.neg(r))) clauses.extend(encode_eq_neg(l, r)) else: eqs.append(Term.mk_equals(l, st)) clauses.append(get_var(len(subterms) - 1)) # Final proposition: under the equality assumptions and the original # term t, can derive the conjunction of the clauses. th = Thm(eqs + [t], logic.mk_conj(*clauses)) # Final CNF: for each clause, get the list of disjuncts. cnf = [] def literal(t): if logic.is_neg(t): return (t.arg.name, False) else: return (t.name, True) for clause in clauses: cnf.append(list(literal(t) for t in logic.strip_disj(clause))) return cnf, th
def ineq_cond(self, e1, e2): return logic.neg(Term.mk_equals(e1, e2))
def nat_const_ineq(thy, a, b): goal = logic.neg(Term.mk_equals(a, b)) return ProofTermDeriv("nat_const_ineq", thy, goal, [])