def if_A3(F): # (!B->!A) -> ((!B->A)->B) # ________ ____________ # F1 F2 try: F1 = F.left F2 = F.right B = F2.right A = F2.left.right nB = notFormula(B) nA = notFormula(A) if F1.left == nB and F1.right == nA and \ F2 == Node(Node(nB, A), B): return True a3 = A3(A, B) if a3 == F: return True except: # F is variable or does not have left or right Node pass return False
def build_deduction(hypoth, F, G, proof=[]): """ hypoth, F |- G => hypoth |- F->G proof = [F1, ..., Fn-1] + [G] F = Fn """ if len(proof) == 0 or proof[-1] != G: proof.append(G) res = [] P_index = -1 for p in proof: P_index += 1 if p == F: res.extend(build_TL(F)) elif axiom.if_Axiom(p) or p in hypoth: # A1 for F, G F1 = axiom.A1(p, F) # MP for F and F1 F2 = axiom.MP(p, F1) res.extend([F1, F2]) else: # smth weird happens here _str = p.msg if not _str.startswith("MP for"): continue _str = _str.replace("MP for", "") sFr, sFs = _str.split(',') Fr = formula.buildFormula(formula.prepareString(sFr)) Fs = formula.buildFormula(formula.prepareString(sFs)) # A2 for G, Fr, F F1 = axiom.A2(F, Fr, p) # MP for F1, G->Fs F2 = axiom.MP(Node(F, Fs), F1) # MP for G->Fr, F2 F3 = axiom.MP(Node(F, Fr), F2) res.extend([F1, F2, F3]) return res
def A1(F, G): """ F -> (G -> F) axiom (1) """ if F is None or G is None: return None tree = Node(G, F) tree = Node(F, tree) tree.msg = "A1 for " + str(F) + ", " + str(G) return tree
def build_T7(F, G): # (F->G)->((!F->G)->G) nF = notFormula(F) nG = notFormula(G) F1 = Node(F, G) F1.msg = "t7 hypoth" F2 = Node(nF, G) F2.msg = "t7 hypoth" f3 = build_T5(F, G) F3 = f3[-1] F4 = axiom.A3(F, G) f5 = syl_1(F3, F4) F5 = f5[-1] F6 = MP(F1, F5) f7 = build_T4(nG, F) F7 = f7[-1] # (!F->G)->(!F->!!G) F8 = nF F9 = Node(nF, G) F10 = MP(F8, F9) f11 = build_T2(G) F11 = f11[-1] F12 = MP(F10, F11) f13 = build_deduction([F1, F2, F9], F8, F12, [F8, F9, F10] + f11 + [F12]) F13 = f13[-1] f14 = build_deduction([], F9, F13, f13) F14 = f14[-1] #... f15 = syl_1(F14, F7) F15 = f15[-1] f16 = syl_1(F15, F6) F16 = f16[-1] proof = [F1, F2] + f14 + [F4] + f5 f17 = build_deduction([], F1, F16, proof) proof = f17 return proof
def T3(F, G): """ !F -> (F->G) """ if type(F) is Node: nf = Node(F.left, F.right, _not=not F._not) else: nf = Variable(F.symbol, _not=not F._not) fg = Node(F, G) msg = "T3 for " + str(F) + ", " + str(G) return Node(nf, fg, msg=msg)
def build_TL(F): """ Make L theorem with F :param F: Variable or Node :return: list of formal conclusions to get F->F """ ff = Node(F, F) # A2 for F, F->F, F F1 = axiom.A2(F, ff, F) # A1 for F, F->F F2 = axiom.A1(F, ff) # MP for F1 and F2 F3 = axiom.MP(F2, F1) # A1 for F and F F4 = axiom.A1(F, F) # MP for F3, F4 F5 = axiom.MP(F3, F4) return [F1, F2, F3, F4, F5]
def T6(F, G): """ F -> (!G -> !(F->G) ) """ if type(G) is Node: ng = Node(G.left, G.right, _not=not G._not) else: ng = Variable(G.symbol, _not=not G._not) nFG = Node(F, G, _not=True) f2 = Node(ng, nFG) msg = "T6 for " + str(F) + ", " + str(G) return Node(F, f2, msg=msg)
def T7(F, G): """ (F->G) -> ( (!F->G) ->G ) """ if type(F) is Node: nf = Node(F.left, F.right, _not=not F._not) else: nf = Variable(F.symbol, _not=not F._not) fg = Node(F, G) nf_g = Node(nf, G) nfg_G = Node(nf_g, G) # (!F->G)->G msg = "T7 for " + str(F) + ", " + str(G) return Node(fg, nfg_G, msg=msg)
def deduction(hypothesis, tree): """ Gamma, F |- G => Gamma |- F->G hypothesis is a node """ msg = "Deduction theorem for " + str(hypothesis) + ", " + str(tree) new_tree = Node(hypothesis, tree, msg=msg) return new_tree
def _create_varfunc(self, quant, name): assert quant != None if not self.debug and self.rename: name = 'VARFUNC' else: name = name.split(':')[0] node = Node(NodeType.VARFUNC, name) node.quant = quant quant.vfunc.append(node) self.graph.append(node) return node
def A3(F, G): """ (!G -> !F) -> ( (!G -> F) -> G ) axiom (3) """ try: notG = notFormula(G) notF = notFormula(F) ngnf = Node(notG, notF) ngf = Node(notG, F) ngf_g = Node(ngf, G) msg = "A3 for " + str(F) + ", " + str(G) return Node(ngnf, ngf_g, msg=msg) except: return None
def T5(F, G): """ (F->G) -> (!G -> !F) """ if type(F) is Node: nf = Node(F.left, F.right, _not=not F._not) else: nf = Variable(F.symbol, _not=not F._not) if type(G) is Node: ng = Node(G.left, G.right, _not=not G._not) else: ng = Variable(G.symbol, _not=not G._not) f1 = Node(F, G) f2 = Node(ng, nf) msg = "T5 for " + str(F) + ", " + str(G) return Node(f1, f2, msg=msg)
def _create_node(self, name): '''Create and return a node Parameters ---------- name : str Name of the node Returns ------- Node A newly created node ''' nname, nodetype = self._name_type(name) node = Node(nodetype, nname) self.graph.append(node) return node
def _create_const(self, name): '''Create and return a Const node Parameters ---------- name : str Name of the constant. Returns ------- Node A newly created constant node ''' node = Node(NodeType.CONST, name) self.graph.append(node) self.scope.declare_const(name, node) return node
def convert(self, formula): '''Convert tupled formula parse tree into graph Parameters ---------- formula : tuple Tupled tree representation of a formula Returns ------- Graph DAG representation of a formula ''' self.scope = Scope() self.graph = [] self.root = None self.tail = None Node.reset_id() append_infer_node = False if isinstance(formula, tuple) and len(formula) == 2 and formula[0] == '|-:c': formula = formula[1] append_infer_node = True while isinstance(formula, tuple) and formula[0] == '!!': formula = formula[2] node = self._formula_to_graph(formula) if self.tail is not None: self.tail.outgoing.append(node) node.incoming.append(self.tail) else: self.root = node if append_infer_node: node = Node(NodeType.CONSTFUNC, '|-:c') self.graph.append(node) node.outgoing.append(self.root) self.root.incoming.append(node) self.root = node if not self.debug: self._finalize_graph() return self.graph
def S1(F1, F2): """ F->G, G->H |- F->H F1 = F->G F2 = G->H """ try: if F1.right == F2.left: msg = "S1 for " + str(F1) + ", " + str(F2) node = Node(F1.right, F2.left, msg=msg) return node except: pass return None
def S2(F1, F2): """ F->(G->H), G |- F->H F1 = F->(G->H) F2 = G """ try: msg = "S2 for " + str(F1) + ", " + str(F2) if F1.right.left == F2: node = Node(F1.left, F1.right.right, msg=msg) except: pass return None
def _create_quant(self, name, free_var=False): '''Create and return a Quant node Parameters ---------- name : str Name of the quantifier. free_var : bool True if quant is associated with a free variable Returns ------- Node A newly created quantifier node ''' node = Node(NodeType.QUANT, name) self.graph.append(node) if not free_var: self.scope.declare_var(node) return node
def build_T4(F, G): # (!G->!F)->(F->G) nF = notFormula(F) nG = notFormula(G) F1 = Node(nG, nF) F2 = F F3 = axiom.A3(F, G) F4 = MP(F1, F3) F5 = axiom.A1(F, nG) f6 = syl_1(F5, F4) proof = [F3, F4, F5] proof.extend(f6) proof = build_deduction([F1, F], F1, f6[-1], proof) return proof
def A2(F, G, H): """ (F -> (G -> H)) -> ( (F -> G) -> (F -> H) ) axiom (2) """ gh = Node(G, H) fgh = Node(F, gh) fg = Node(F, G) fh = Node(F, H) fgfh = Node(fg, fh) msg = "A2 for " + str(F) + ", " + str(G) + ", " + str(H) res = Node(fgh, fgfh, msg=msg) return res
def build_T5(F, G): """ (F->G)->(!G->!F) """ nF = notFormula(F) nG = notFormula(G) nnF = notFormula(nF) nnG = notFormula(nG) F1 = Node(F, G) f2 = build_T2(G) F2 = f2[-1] F3 = axiom.A3(nG, nF) f4 = syl_1(F1, F2) # f->!!g F4 = f4[-1] f5 = build_T1(F) F5 = f5[-1] f6 = syl_1(F5, F4) # !!f->!!g F6 = f6[-1] F7 = MP(F6, F3) # (!!f->!g)->!f F8 = axiom.A1(nG, nnF) f9 = syl_1(F8, F7) F9 = f9[-1] proof = f2 + [F3] + f4 + f5 + f6 + [F7, F8] + f9 proof = build_deduction([F1, nG], F1, F9, proof) return proof
def build_T6(F, G): fg = Node(F, G) fg.msg = "hypoth t6" t5 = build_T5(fg, G) T5 = t5[-1] ng = notFormula(G) ng.msg = "hypoth t6" F1 = F F1.msg = "hypoth t6" # we need (F->G)->G F2 = MP(F1, fg) ded = build_deduction([F1, ng], fg, G, [F1, F2]) F3 = ded[-1] F4 = MP(F3, T5) proof = [F1, ng, F2] + ded + [F4] proof = build_deduction([], F, F4, proof) return proof
def _create_var(self, quant, name): '''Create and return a Var node This function won't declare the variable! Parameters ---------- quant : Quant Quantifier that quantifies this variable. Returns ------- Node A newly created variable node ''' assert quant != None if not self.debug and self.rename: name = 'VAR' else: name = name.split(':')[0] node = Node(NodeType.VAR, name) node.quant = quant quant.vvalue = node self.graph.append(node) return node
return False def if_Axiom(F): """ Check if F is Axiom """ return if_A1(F) or if_A2(F) or if_A3(F) if __name__ == '__main__': f1 = Variable('F') f2 = Node(Variable('F'), Variable('G')) print(MP(f1, f2)) exit() f1 = "(A->B)" f2 = "(A->!(B->!C))" tests = [ "F->(G->F)", "G->(F->G)", "F->(F->F)", "!F->((A->B)->!F)", "(A->(B->C))->((A->B)->(A->C))", "({0}->(B->{1}))->(({0}->B)->({0}->{1}))".format(f1, f2), "(!G->!F)->((!G->F)->G)", "(!G->!G)->((!G->G)->G)", "(!(f1)->!(f2))->((!(f1)->(f2))->(f1))".replace('f1', f1).replace('f2', f2) ] from formula import prepareString, buildFormula, IncorrectInput
def _create_constfunc(self, name): node = Node(NodeType.CONSTFUNC, name) self.graph.append(node) return node
def Calmar_Theorem(F, values): ''' Calmar's Theorem implementation :param F: Propositional calculus formula: Variable or Node :return: ''' if type(F) == Variable: v = Variable(F.symbol, _not=True if values[F.symbol] == 1 else 0) return [v] if F._not: # F = !G G = Node(None, None) G.left = F.left # Copy G, but F = !G G.right = F.right if F.calculate(values) == 1: G.msg = "Calmar's theorem, 1.a) F^(alpha) = G^(alpha) => hypoth |- G^() = F^()" return [G] else: # !f = !!g t2 = build_T2(G) T2 = t2[-1] nng = MP(G, T2) res = t2 res.append(nng) return res else: # F = G->H res = [] G = F.left H = F.right if G.calculate(values) == 0: nG = notFormula(G) t3 = build_T3(G, H) T = t3[-1] mp = MP(nG, T) res = t3 res.append(mp) elif H.calculate(values) == 1: # h->(g->h) h = H hgh = axiom.A1(H, G) gh = MP(h, hgh) return [hgh, gh] else: # F = !(G->H) # have G, !H. proof !(G->H) nH = notFormula(H) t6 = build_T6(G, H) T6 = t6[-1] f1 = MP(G, T6) f2 = MP(nH, f1) res = t6 res.extend([f1, f2]) return res
def TL(F): msg = "L theorem for " + str(F) return Node(F, F, msg=msg)
proof.extend(deductC2) proof.extend(t7) proof.extend([mp1, mp2]) curLen = len(proof) #for debug vector += 1 n += 1 return proof if __name__ == '__main__': f = Variable('F') g = Variable('G') nf = notFormula(f) nnf = notFormula(nf) Ad_Theorem(Node(nnf, f)) t4 = build_T4(f, g) T4 = t4[-1] t5 = build_T5(f, g) t6 = build_T6(f, g) t7 = build_T7(f, g) T7 = t7[-1] print('no exception? it is small victory')