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 testConjCommWithMacro(self): """Proof of commutativity of conjunction, with macros.""" thy = basic.load_theory('logic_base') A = Var("A", boolT) B = Var("B", boolT) prf = Proof(logic.mk_conj(A, B)) prf.add_item(1, "apply_theorem", args="conjD1", prevs=[0]) prf.add_item(2, "apply_theorem", args="conjD2", prevs=[0]) prf.add_item(3, "apply_theorem", args="conjI", prevs=[2, 1]) prf.add_item(4, "implies_intr", args=logic.mk_conj(A, B), prevs=[3]) th = Thm.mk_implies(logic.mk_conj(A, B), logic.mk_conj(B, A)) self.assertEqual(thy.check_proof(prf), th)
def testConjComm(self): """Proof of commutativity of conjunction.""" thy = basic.load_theory('logic_base') A = Var("A", boolT) B = Var("B", boolT) prf = Proof(logic.mk_conj(A, B)) prf.add_item(1, "theorem", args="conjD1") prf.add_item(2, "implies_elim", prevs=[1, 0]) prf.add_item(3, "theorem", args="conjD2") prf.add_item(4, "implies_elim", prevs=[3, 0]) prf.add_item(5, "theorem", args="conjI") prf.add_item(6, "substitution", args={"A": B, "B": A}, prevs=[5]) prf.add_item(7, "implies_elim", prevs=[6, 4]) prf.add_item(8, "implies_elim", prevs=[7, 2]) prf.add_item(9, "implies_intr", args=logic.mk_conj(A, B), prevs=[8]) th = Thm.mk_implies(logic.mk_conj(A, B), logic.mk_conj(B, A)) self.assertEqual(thy.check_proof(prf), th)
def testParseThm(self): test_data = [ ("|- A", Thm([], A)), ("|- A & B", Thm([], logic.mk_conj(A, B))), ("A |- B", Thm([A], B)), ("A, B |- C", Thm([A, B], C)), ] for s, th in test_data: self.assertEqual(parser.parse_thm(thy, ctxt, s), th)
def testApplyTheorem(self): thy = basic.load_theory('logic_base') A = Var("A", boolT) B = Var("B", boolT) th = Thm([logic.mk_conj(A, B)], A) prf = Proof(logic.mk_conj(A, B)) prf.add_item(1, "apply_theorem", args="conjD1", prevs=[0]) rpt = ProofReport() self.assertEqual(thy.check_proof(prf, rpt), th) self.assertEqual(rpt.prim_steps, 4) # Reset data for the next check prf = Proof(logic.mk_conj(A, B)) prf.add_item(1, "apply_theorem", args="conjD1", prevs=[0]) rpt = ProofReport() self.assertEqual(thy.check_proof(prf, rpt, check_level=1), th) self.assertEqual(rpt.prim_steps, 1) self.assertEqual(rpt.macro_steps, 1)
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 testAllConjWithMacro(self): """Proof of (!x. A x & B x) --> (!x. A x) & (!x. B x), using macros.""" 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, "apply_theorem", args="conjD1", prevs=[1]) prf.add_item(3, "forall_intr", args=x, prevs=[2]) prf.add_item(4, "apply_theorem", args="conjD2", prevs=[1]) prf.add_item(5, "forall_intr", args=x, prevs=[4]) prf.add_item(6, "apply_theorem", args="conjI", prevs=[3, 5]) prf.add_item(7, "implies_intr", args=all_conj, prevs=[6]) th = Thm.mk_implies(all_conj, conj_all) self.assertEqual(thy.check_proof(prf), th)
def testExistsConjWithMacro(self): """Proof of (?x. A x & B x) --> (?x. A x) & (?x. B x), using macros.""" 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) conjAB = logic.mk_conj(A(x), B(x)) exists_conj = logic.mk_exists(x, conjAB) exists_A = logic.mk_exists(x, A(x)) exists_B = logic.mk_exists(x, B(x)) conj_exists = logic.mk_conj(exists_A, exists_B) prf = Proof(exists_conj) prf.add_item(1, "assume", args=conjAB) prf.add_item(2, "apply_theorem", args="conjD1", prevs=[1]) prf.add_item(3, "apply_theorem", args="conjD2", prevs=[1]) prf.add_item(4, "apply_theorem_for", args=("exI", {}, { 'P': A, 'a': x }), prevs=[2]) prf.add_item(5, "apply_theorem_for", args=("exI", {}, { 'P': B, 'a': x }), prevs=[3]) prf.add_item(6, "apply_theorem", args="conjI", prevs=[4, 5]) prf.add_item(7, "implies_intr", args=conjAB, prevs=[6]) prf.add_item(8, "forall_intr", args=x, prevs=[7]) prf.add_item(9, "apply_theorem", args="exE", prevs=[0, 8]) prf.add_item(10, "implies_intr", args=exists_conj, prevs=[9]) th = Thm.mk_implies(exists_conj, conj_exists) self.assertEqual(thy.check_proof(prf), th)
def testTrueAbsorb(self): """Proof of A --> true & A.""" thy = basic.load_theory('logic_base') A = Var("A", boolT) prf = Proof(A) prf.add_item(1, "theorem", args="trueI") prf.add_item(2, "theorem", args="conjI") prf.add_item(3, "substitution", args={ "A": logic.true, "B": A }, prevs=[2]) prf.add_item(4, "implies_elim", prevs=[3, 1]) prf.add_item(5, "implies_elim", prevs=[4, 0]) prf.add_item(6, "implies_intr", args=A, prevs=[5]) th = Thm.mk_implies(A, logic.mk_conj(logic.true, A)) self.assertEqual(thy.check_proof(prf), th)
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 conj(self, s, t): return logic.mk_conj(s, t)
def testParseProofRule(self): test_data = [ ({ 'id': "0", 'rule': "theorem", 'args': "conjD1", 'prevs': [], 'th': "" }, ProofItem(0, "theorem", args="conjD1", prevs=[])), ({ 'id': "2", 'rule': "implies_elim", 'args': "", 'prevs': ["1", "0"], 'th': "" }, ProofItem(2, "implies_elim", prevs=[1, 0])), ({ 'id': "5", 'rule': "substitution", 'args': "{A: B, B: A}", 'prevs': ["4"], 'th': "" }, ProofItem(5, "substitution", args={ 'A': B, 'B': A }, prevs=[4])), ({ 'id': "8", 'rule': "implies_intr", 'args': "conj A B", 'prevs': ["7"], 'th': "" }, ProofItem(8, "implies_intr", args=logic.mk_conj(A, B), prevs=[7])), ({ 'id': "0", 'rule': "sorry", 'args': "", 'prevs': [], 'th': "conj A B |- conj B A" }, ProofItem(0, "sorry", th=Thm([logic.mk_conj(A, B)], logic.mk_conj(B, A)))), ({ 'id': "1", 'rule': "", 'args': "", 'prevs': [], 'th': "" }, ProofItem(1, "")), ({ 'id': "5", 'rule': "apply_theorem_for", 'args': "disjI1, {}, {A: B, B: A}", 'prevs': [4], 'th': "" }, ProofItem(5, "apply_theorem_for", args=("disjI1", {}, { 'A': B, 'B': A }), prevs=[4])), ] for s, res in test_data: self.assertEqual(parser.parse_proof_rule(thy, ctxt, s), res)
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 testStripConj(self): test_data = [(a, [a]), (logic.mk_conj(a, b, a), [a, b, a])] for t, res in test_data: self.assertEqual(logic.strip_conj(t), res)
def testConj(self): test_data = [([], logic.true), ([a], a), ([a, b], logic.conj(a, b)), ([a, b, a], logic.conj(a, logic.conj(b, a)))] for ts, res in test_data: self.assertEqual(logic.mk_conj(*ts), res)
def testExistsConj(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) conjAB = logic.mk_conj(A(x), B(x)) exists_conj = logic.mk_exists(x, conjAB) exists_A = logic.mk_exists(x, A(x)) exists_B = logic.mk_exists(x, B(x)) conj_exists = logic.mk_conj(exists_A, exists_B) prf = Proof(exists_conj) prf.add_item(1, "assume", args=conjAB) 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, "theorem", args="conjD2") prf.add_item(6, "substitution", args={"A": A(x), "B": B(x)}, prevs=[5]) prf.add_item(7, "implies_elim", prevs=[6, 1]) prf.add_item(8, "theorem", args="exI") prf.add_item(9, "substitution", args={"P": A, "a": x}, prevs=[8]) prf.add_item(10, "implies_elim", prevs=[9, 4]) prf.add_item(11, "substitution", args={"P": B, "a": x}, prevs=[8]) prf.add_item(12, "implies_elim", prevs=[11, 7]) prf.add_item(13, "implies_intr", args=conjAB, prevs=[10]) prf.add_item(14, "implies_intr", args=conjAB, prevs=[12]) prf.add_item(15, "forall_intr", args=x, prevs=[13]) prf.add_item(16, "forall_intr", args=x, prevs=[14]) prf.add_item(17, "theorem", args="exE") prf.add_item(18, "substitution", args={ "P": Term.mk_abs(x, conjAB), "C": exists_A }, prevs=[17]) prf.add_item(19, "beta_norm", prevs=[18]) prf.add_item(20, "implies_elim", prevs=[19, 0]) prf.add_item(21, "implies_elim", prevs=[20, 15]) prf.add_item(22, "substitution", args={ "P": Term.mk_abs(x, conjAB), "C": exists_B }, prevs=[17]) prf.add_item(23, "beta_norm", prevs=[22]) prf.add_item(24, "implies_elim", prevs=[23, 0]) prf.add_item(25, "implies_elim", prevs=[24, 16]) prf.add_item(26, "theorem", args="conjI") prf.add_item(27, "substitution", args={ "A": exists_A, "B": exists_B }, prevs=[26]) prf.add_item(28, "implies_elim", prevs=[27, 21]) prf.add_item(29, "implies_elim", prevs=[28, 25]) prf.add_item(30, "implies_intr", args=exists_conj, prevs=[29]) th = Thm.mk_implies(exists_conj, conj_exists) self.assertEqual(thy.check_proof(prf), th)