def get_proof_term(self, t): def strip_conj_all(t): if t.is_conj(): return strip_conj_all(t.arg1) + strip_conj_all(t.arg) else: return [t] conj_terms = term_ord.sorted_terms(strip_conj_all(t)) goal = Eq(t, And(*conj_terms)) return imp_conj_iff(goal)
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 convert_cnf_to_HOL(cnf_file): disjs = read_cnf_file(cnf_file) tms = [] for disj in disjs: lits = [] for var, stat in disj: if stat: lits.append(Var(var, BoolType)) else: lits.append(Not(Var(var, BoolType))) tms.append(Or(*lits)) return And(*tms)
def testPrintUnicode(self): test_data = [ (And(A, B), "A ∧ B"), (Or(A, B), "A ∨ B"), (Implies(A, B), "A ⟶ B"), (Lambda(a, P(a)), "λa. P a"), (Forall(a, P(a)), "∀a. P a"), (Exists(a, P(a)), "∃a. P a"), (Not(A), "¬A"), (Lambda(m, m + 2), "λm::nat. m + 2"), (Lambda(m, m + n), "λm. m + n"), ] with global_setting(unicode=True): for t, s in test_data: self.assertEqual(printer.print_term(t), s)
def testParseThm(self): A = Var('A', BoolType) B = Var('B', BoolType) C = Var('C', BoolType) test_data = [ ("|- A", Thm([], A)), ("|- A & B", Thm([], And(A, B))), ("A |- B", Thm([A], B)), ("A, B |- C", Thm([A, B], C)), ] context.set_context('logic', vars={ 'A': 'bool', 'B': 'bool', 'C': 'bool' }) for s, th in test_data: self.assertEqual(parser.parse_thm(s), th)
def nnf(fm): """Negation normal form of a formula.""" if fm.is_conj(): return And(nnf(fm.arg1), nnf(fm.arg)) elif fm.is_disj(): return Or(nnf(fm.arg1), nnf(fm.arg)) elif fm.is_implies(): return Or(nnf(Not(fm.arg1)), nnf(fm.arg)) elif fm.is_equals(): return Or(And(nnf(fm.arg1), nnf(fm.arg)), And(nnf(Not(fm.arg1)), nnf(Not(fm.arg)))) elif fm.is_not(): p = fm.arg if p.is_not(): return nnf(p.arg) elif p.is_conj(): return Or(nnf(Not(p.arg1)), nnf(Not(p.arg))) elif p.is_disj(): return And(nnf(Not(p.arg1)), nnf(Not(p.arg))) elif p.is_implies(): return And(nnf(p.arg1), nnf(Not(p.arg))) elif p.is_equals(): return Or(And(nnf(p.arg1), nnf(Not(p.arg))), And(nnf(Not(p.arg1)), nnf(p.arg))) elif p.is_forall(): assert p.arg.is_abs() return term.exists(p.arg.var_T)(Abs(p.arg.var_name, p.arg.var_T, nnf(Not(p.arg.body)))) elif p.is_exists(): assert p.arg.is_abs() return term.forall(p.arg.var_T)(Abs(p.arg.var_name, p.arg.var_T, nnf(Not(p.arg.body)))) else: return fm elif fm.is_forall() or fm.is_exists(): assert fm.arg.is_abs() return fm.fun(Abs(fm.arg.var_name, fm.arg.var_T, nnf(fm.arg.body))) else: return fm
def testPrintLogical(self): test_data = [ # Variables (SVar("P", BoolType), "?P"), (a, "a"), # Equality and implies (Eq(a, b), "a = b"), (Implies(A, B), "A --> B"), (Implies(A, B, C), "A --> B --> C"), (Implies(Implies(A, B), C), "(A --> B) --> C"), (Implies(A, Eq(a, b)), "A --> a = b"), (Eq(Implies(A, B), Implies(B, C)), "(A --> B) <--> (B --> C)"), (Eq(A, Eq(B, C)), "A <--> B <--> C"), (Eq(Eq(A, B), C), "(A <--> B) <--> C"), # Conjunction and disjunction (And(A, B), "A & B"), (Or(A, B), "A | B"), (And(A, And(B, C)), "A & B & C"), (And(And(A, B), C), "(A & B) & C"), (Or(A, Or(B, C)), "A | B | C"), (Or(Or(A, B), C), "(A | B) | C"), (Or(And(A, B), C), "A & B | C"), (And(Or(A, B), C), "(A | B) & C"), (Or(A, And(B, C)), "A | B & C"), (And(A, Or(B, C)), "A & (B | C)"), (Or(And(A, B), And(B, C)), "A & B | B & C"), (And(Or(A, B), Or(B, C)), "(A | B) & (B | C)"), # Negation (Not(A), "~A"), (Not(Not(A)), "~~A"), # Constants (true, "true"), (false, "false"), # Mixed (Implies(And(A, B), C), "A & B --> C"), (Implies(A, Or(B, C)), "A --> B | C"), (And(A, Implies(B, C)), "A & (B --> C)"), (Or(Implies(A, B), C), "(A --> B) | C"), (Not(And(A, B)), "~(A & B)"), (Not(Implies(A, B)), "~(A --> B)"), (Not(Eq(A, B)), "~(A <--> B)"), (Eq(Not(A), B), "~A <--> B"), (Eq(Not(A), Not(B)), "~A <--> ~B"), (Implies(A, Eq(B, C)), "A --> B <--> C"), (Eq(Implies(A, B), C), "(A --> B) <--> C"), # Abstraction (Lambda(a, And(P(a), Q(a))), "%a. P a & Q a"), # Quantifiers (Forall(a, P(a)), "!a. P a"), (Forall(a, Forall(b, And(P(a), P(b)))), "!a. !b. P a & P b"), (Forall(a, And(P(a), Q(a))), "!a. P a & Q a"), (And(Forall(a, P(a)), Q(a)), "(!a1. P a1) & Q a"), (Forall(a, Implies(P(a), Q(a))), "!a. P a --> Q a"), (Implies(Forall(a, P(a)), Q(a)), "(!a1. P a1) --> Q a"), (Implies(Forall(a, P(a)), Forall(a, Q(a))), "(!a. P a) --> (!a. Q a)"), (Implies(Exists(a, P(a)), Exists(a, Q(a))), "(?a. P a) --> (?a. Q a)"), (Eq(A, Forall(a, P(a))), "A <--> (!a. P a)"), (Exists(a, P(a)), "?a. P a"), (Exists(a, Forall(b, R(a, b))), "?a. !b. R a b"), (logic.mk_exists1(a, P(a)), "?!a. P a"), (logic.mk_the(a, P(a)), "THE a. P a"), (logic.mk_some(a, P(a)), "SOME a. P a"), (Forall(a, Exists(b, R(a, b))), "!a. ?b. R a b"), # If (mk_if(A, a, b), "if A then a else b"), (Eq(mk_if(A, a, b), a), "(if A then a else b) = a"), (mk_if(A, P, Q), "if A then P else Q"), ] with global_setting(unicode=False): for t, s in test_data: self.assertEqual(printer.print_term(t), s)
def testStripConj(self): test_data = [(a, [a]), (And(a, b, a), [a, b, a])] for t, res in test_data: self.assertEqual(t.strip_conj(), res)
def testConj(self): test_data = [([], term.true), ([a], a), ([a, b], term.conj(a, b)), ([a, b, a], term.conj(a, term.conj(b, a)))] for ts, res in test_data: self.assertEqual(And(*ts), res)
def get_proof_term(self, t): if not t.is_conj(): return refl(t) d_pos = dict() d_neg = dict() qu = deque([ProofTerm.assume(t)]) # collect each conjunct's proof term in conjuntion while qu: pt = qu.popleft() if pt.prop.is_conj(): conj1, conj2 = pt.prop.arg1, pt.prop.arg pt_conj1, pt_conj2 = apply_theorem('conjD1', pt), apply_theorem( 'conjD2', pt) if conj1 == false: th = ProofTerm.theorem("falseE") inst = matcher.first_order_match(th.prop.arg, t) pt_false_implies_conj = th.substitution(inst) return ProofTerm.equal_intr(pt_conj1.implies_intr(t), pt_false_implies_conj) elif conj2 == false: th = ProofTerm.theorem("falseE") inst = matcher.first_order_match(th.prop.arg, t) pt_false_implies_conj = th.substitution(inst) return ProofTerm.equal_intr(pt_conj2.implies_intr(t), pt_false_implies_conj) if conj1.is_conj(): qu.appendleft(pt_conj1) else: if conj1.is_not(): d_neg[conj1] = pt_conj1 else: d_pos[conj1] = pt_conj1 if conj2.is_conj(): qu.appendleft(pt_conj2) else: if conj2.is_not(): d_neg[conj2] = pt_conj2 else: d_pos[conj2] = pt_conj2 else: if pt.prop.is_not(): d_neg[pt.prop] = pt else: d_pos[pt.prop] = pt # first check if there are opposite terms in conjunctions, if there exists, return a false proof term for key in d_pos: if Not(key) in d_neg: pos_pt, neg_pt = d_pos[key], d_neg[Not(key)] pt_conj_pos_neg = apply_theorem("conjI", pos_pt, neg_pt) pt_conj_implies_false = pt_conj_pos_neg.on_prop( rewr_conv("conj_pos_neg")).implies_intr(t) th = ProofTerm.theorem("falseE") inst = matcher.first_order_match(th.prop.arg, t) pt_false_implies_conj = th.substitution(inst) return ProofTerm.equal_intr(pt_conj_implies_false, pt_false_implies_conj) d_pos.update(d_neg) d = d_pos def right_assoc(ts): l = len(ts) if l == 1: return d[ts[0]] elif l == 2: return apply_theorem('conjI', d[ts[0]], d[ts[1]]) else: return apply_theorem('conjI', d[ts[0]], right_assoc(ts[1:])) # pt_right = functools.reduce(lambda x, y: apply_theorem('conjI', x, d[y]), sorted(d.keys()), d[sorted(d.keys())[0]]) if true not in d: sorted_keys = term_ord.sorted_terms(d.keys()) else: d_keys_without_true = term_ord.sorted_terms( [k for k in d if k != true]) sorted_keys = [true] + d_keys_without_true sorted_keys_num = len(sorted_keys) pt_right = functools.reduce(lambda x, y: apply_theorem('conjI', d[sorted_keys[sorted_keys_num - y - 2]], x), \ range(sorted_keys_num - 1), d[sorted_keys[-1]]) # pt_right = right_assoc(sorted_keys) # order implies original dd = dict() norm_conj = And(*sorted_keys) norm_conj_pt = ProofTerm.assume(norm_conj) for k in sorted_keys: if k != sorted_keys[-1]: dd[k] = apply_theorem('conjD1', norm_conj_pt) norm_conj_pt = apply_theorem('conjD2', norm_conj_pt) else: dd[k] = norm_conj_pt def traverse(t): if not t.is_conj(): return dd[t] else: return apply_theorem('conjI', traverse(t.arg1), traverse(t.arg)) pt_left = traverse(t) pt_final = ProofTerm.equal_intr(pt_right.implies_intr(t), pt_left.implies_intr(norm_conj)) if true in d: return pt_final.on_rhs(rewr_conv("conj_true_left"), top_sweep_conv(sort_disj())) else: return pt_final.on_rhs(top_sweep_conv(sort_disj()))
def conj(self, s, t): return And(s, t)
def testParseProofRule(self): A = Var('A', BoolType) B = Var('B', BoolType) 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=Inst(A=B, B=A), prevs=[4])), ({ 'id': "8", 'rule': "implies_intr", 'args': "conj A B", 'prevs': ["7"], 'th': "" }, ProofItem(8, "implies_intr", args=And(A, B), prevs=[7])), ({ 'id': "0", 'rule': "sorry", 'args': "", 'prevs': [], 'th': "conj A B |- conj B A" }, ProofItem(0, "sorry", th=Thm([And(A, B)], And(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", Inst(A=B, B=A)), prevs=[4])), ] context.set_context('logic_base', vars={'A': 'bool', 'B': 'bool'}) for s, res in test_data: self.assertEqual(parser.parse_proof_rule(s), res)
def conj_cond(self, b1, b2): return And(b1, b2)
def get_extension(self): assert self.error is None, "get_extension" res = [] # Add to type and term signature. res.append(extension.TConst(self.name, len(self.args))) for constr in self.constrs: res.append( extension.Constant(constr['name'], constr['type'], ref_name=constr['cname'])) # Add non-equality theorems. for constr1, constr2 in itertools.combinations(self.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, _ = constr1['type'].strip_type() argT2, _ = constr2['type'].strip_type() lhs_vars = [Var(nm, T) for nm, T in zip(constr1['args'], argT1)] rhs_vars = [Var(nm, T) for nm, T in zip(constr2['args'], argT2)] A = Const(constr1['name'], constr1['type']) B = Const(constr2['name'], constr2['type']) lhs = A(*lhs_vars) rhs = B(*rhs_vars) neq = Not(Eq(lhs, rhs)) th_name = "%s_%s_%s_neq" % (self.name, constr1['name'], constr2['name']) res.append(extension.Theorem(th_name, Thm([], neq))) # Add injectivity theorems. for constr in self.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 constr['args']: argT, _ = constr['type'].strip_type() lhs_vars = [Var(nm, T) for nm, T in zip(constr['args'], argT)] rhs_vars = [ Var(nm + "1", T) for nm, T in zip(constr['args'], argT) ] A = Const(constr['name'], constr['type']) assum = Eq(A(*lhs_vars), A(*rhs_vars)) concls = [ Eq(var1, var2) for var1, var2 in zip(lhs_vars, rhs_vars) ] concl = And(*concls) th_name = "%s_%s_inject" % (self.name, constr['name']) res.append( extension.Theorem(th_name, Thm([], Implies(assum, concl)))) # Add the inductive theorem. tvars = [TVar(targ) for targ in self.args] T = TConst(self.name, *tvars) var_P = Var("P", TFun(T, BoolType)) ind_assums = [] for constr in self.constrs: A = Const(constr['name'], constr['type']) argT, _ = constr['type'].strip_type() args = [Var(nm, T2) for nm, T2 in zip(constr['args'], argT)] C = var_P(A(*args)) As = [ var_P(Var(nm, T2)) for nm, T2 in zip(constr['args'], argT) if T2 == T ] ind_assum = Implies(*(As + [C])) for arg in reversed(args): ind_assum = Forall(arg, ind_assum) ind_assums.append(ind_assum) ind_concl = var_P(Var("x", T)) th_name = self.name + "_induct" res.append( extension.Theorem(th_name, Thm([], Implies(*(ind_assums + [ind_concl]))))) res.append(extension.Attribute(th_name, "var_induct")) return res