def step(self, s): s = U(s) if not (self.handwaving or self.is_valid_new_theorem(s)): raise InvalidStep() self.handwaving = False self.theorems.add(s) self.conclusion = s
def is_valid_by_detachment(self, s): s = U(s) for theorem in self.theorems: implication = u'<%s⊃%s>' % (theorem, s) if implication in self.theorems: return True # because of the implication return False
def is_valid_by_interchange(self, s): s = U(s) for theorem in self.theorems: if len(theorem) == len(s): a = theorem.find(u'∀') while a >= 0 and s[:a] == theorem[:a]: if s[a:a + 2] == u'~∃': colon = theorem.find(':', a + 1) u = theorem[a + 1:colon] assert is_variable(u) if theorem[colon + 1] == '~': if s == theorem[:a] + u'~∃' + u + ':' + theorem[ colon + 2:]: return True a = theorem.find(u'∀', a + 1) ne = theorem.find(u'~∃') while ne >= 0 and s[:ne] == theorem[:ne]: if s[ne] == u'∀': colon = theorem.find(':', ne + 2) u = theorem[ne + 2:colon] assert is_variable(u) if s == theorem[:ne] + u'∀' + u + ':~' + theorem[ colon + 1:]: return True ne = theorem.find(u'~∃', ne + 2) return False
def is_valid_by_joining(self, s): s = U(s) if s[0] == '<' and s[-1] == '>': for i in range(len(s)): if s[i] == u'∧': first, second = s[1:i], s[i + 1:-1] if set([first, second]) <= self.theorems: return True return False
def is_valid_by_double_tilde(self, s): s = U(s) if not wff.is_well_formed_formula(s): return False for theorem in self.theorems: if self.is_removal_of_double_tilde( s, theorem) or self.is_removal_of_double_tilde(theorem, s): return True return False
def is_valid_by_separation(self, s): s = U(s) if not wff.is_well_formed_formula(s): return False for theorem in self.theorems: if theorem[0] == '<' and theorem[-1] == '>': if theorem.startswith(u'<%s∧' % s): return True if theorem.endswith(u'∧%s>' % s): return True return False
def is_valid_by_existence(self, s): s = U(s) if s.startswith(u'∃'): colon = s.find(':') if colon >= 0: u, x = s[1:colon], s[colon + 1:] if is_variable(u) and u in wff.get_free_variables(x): for theorem in self.theorems: if self._is_substitution_of_some_term_for_variable( u, x, theorem): return True return False
def is_valid_by_specification(self, s): s = U(s) for theorem in self.theorems: if theorem.startswith(u'∀'): colon = theorem.find(':') if colon >= 0: u, x = theorem[1:colon], theorem[colon + 1:] assert is_variable(u) if self._is_substitution_of_some_term_for_variable( u, x, s): return True return False
def is_valid_by_induction(self, s): s = U(s) if wff.is_well_formed_formula(s) and s[0] == u'∀': colon = s.find(':') assert colon >= 0 u, x = s[1:colon], s[colon + 1:] assert is_variable(u) base_case = x.replace(u, '0') if base_case in self.theorems: inductive_case = u'∀%s:<%s⊃%s>' % (u, x, x.replace(u, 'S' + u)) if inductive_case in self.theorems: return True return False
def is_valid_by_generalization(self, s): s = U(s) if s.startswith(u'∀'): colon = s.find(':') if colon >= 0: u, x = s[1:colon], s[colon + 1:] if wff.is_variable(u) and u in wff.get_free_variables(x): if self.premise is not None and u in wff.get_free_variables( self.premise): return False if x in self.theorems: return True return False
def is_valid_by_successorship(self, s): s = U(s) equals = s.find('=') if equals > 0: first, second = s[:equals], s[equals + 1:] if is_term(first) and is_term(second): add_s = u'S%s=S%s' % (first, second) if add_s in self.theorems: return True if first[0] == 'S' and second[0] == 'S': drop_s = u'%s=%s' % (first[1:], second[1:]) if drop_s in self.theorems: return True return False
def is_valid_new_theorem(self, s): s = U(s) return ((s in self.theorems) or self.is_valid_by_joining(s) or self.is_valid_by_separation(s) or self.is_valid_by_double_tilde(s) or self.is_valid_by_detachment(s) or self.is_valid_by_contrapositive(s) or self.is_valid_by_de_morgans(s) or self.is_valid_by_switcheroo(s) or self.is_valid_by_specification(s) or self.is_valid_by_generalization(s) or self.is_valid_by_interchange(s) or self.is_valid_by_existence(s) or self.is_valid_by_equality(s) or self.is_valid_by_successorship(s) or self.is_valid_by_induction(s) or False)
def is_valid_by_equality(self, s): s = U(s) equals = s.find('=') if equals > 0: first, second = s[:equals], s[equals + 1:] if is_term(first) and is_term(second): symmetrical_s = u'%s=%s' % (second, first) if symmetrical_s in self.theorems: return True for theorem in self.theorems: if theorem.startswith(first + '='): middle = theorem[len(first) + 1:] transitive_s = u'%s=%s' % (middle, second) if transitive_s in self.theorems: return True return False
def _is_valid_by_substituting(self, s, a, b): s = U(s) for xi in range(0, len(s)): for xj in range(xi + 1, len(s)): x = s[xi:xj] if wff.is_well_formed_formula(x): for yi in range(0, len(s)): for yj in range(yi + 1, len(s)): y = s[yi:yj] if wff.is_well_formed_formula(y): first = a.replace('X', x).replace('Y', y) if len(first) > len(s): continue second = b.replace('X', x).replace('Y', y) i = s.find(first) while i != -1: substituted_s = s[:i] + second + s[ i + len(first):] if substituted_s in self.theorems: return True i = s.find(first, i + 1) return False
def fantasy(self, premise): f = Derivation([U(premise), self.theorems.copy()]) yield f s = u'<%s⊃%s>' % (f.premise, f.conclusion) self.theorems.add(s) self.conclusion = s
def check_well_formed_formula(s): s = U(s) opr, opd = [], [] def opr_top(): return opr[-1] if opr else 'X' def opr_push(x): return opr.append(x) def opd_push(x): assert not (x[2] & x[3]) return opd.append(x) nope = FormulaInfo(False, set(), set()) try: for token in re.split(u'(S*0)|(S*[a-z]′*)|(S+)|(.)', s): if not token: continue if is_variable(token): if opr_top() in u'∀∃': opd_push(['V', token, set([token]), set()]) else: opd_push(['T', token, set([token]), set()]) elif re.match(u'(S*0)|(S*[a-z]′*)', token): opd_push( ['T', token, get_free_variables_in_term(token), set()]) elif re.match('S+', token): opr_push(token) elif token in u'<(∀∃:+⋅~': opr_push(token) elif token == '=': if re.match('S+', opr_top()): op = opr.pop() t1 = opd.pop() if t1[0] != 'T': return nope opd_push(['T', op + t1[1], t1[2], set()]) opr_push(token) elif token == ')': t2 = opd.pop() t1 = opd.pop() op = opr.pop() if opr.pop() != '(': return nope if op not in u'+⋅': return nope if t1[0] != 'T' or t2[0] != 'T': return nope opd_push([ 'T', u'(%s%s%s)' % (t1[1], op, t2[1]), t1[2] | t2[2], set() ]) if re.match('S+', opr_top()): op = opr.pop() t1 = opd.pop() opd_push(['T', op + t1[1], t1[2], set()]) elif token in u'∧∨⊃': if re.match('S+', opr_top()): op = opr.pop() t1 = opd.pop() if t1[0] != 'T': return nope opd_push(['T', op + t1[1], t1[2], set()]) if opr_top() == '=': t2 = opd.pop() t1 = opd.pop() op = opr.pop() if t1[0] != 'T' or t2[0] != 'T': return nope opd_push( ['F', u'%s=%s' % (t1[1], t2[1]), t1[2] | t2[2], set()]) while opr_top() in ':~': op = opr.pop() if op == '~': t1 = opd.pop() if t1[0] != 'F': return nope opd_push(['F', u'~%s' % t1[1], t1[2], t1[3]]) elif op == ':': x = opd.pop() v = opd.pop() op = opr.pop() if op not in u'∀∃': return nope if x[0] != 'F' or v[0] != 'V': return nope if v[1] not in x[2]: return nope # v must be free in x opd_push([ 'F', u'%s%s:%s' % (op, v[1], x[1]), x[2] - set([v[1]]), x[3] | set([v[1]]) ]) opr_push(token) elif token == '>': if opr_top() == '=': t2 = opd.pop() t1 = opd.pop() op = opr.pop() if t1[0] != 'T' or t2[0] != 'T': return nope opd_push( ['F', u'%s=%s' % (t1[1], t2[1]), t1[2] | t2[2], set()]) while opr_top() in ':~': op = opr.pop() if op == '~': t1 = opd.pop() if t1[0] != 'F': return nope opd_push(['F', u'~%s' % t1[1], t1[2], t1[3]]) elif op == ':': x = opd.pop() v = opd.pop() op = opr.pop() if op not in u'∀∃': return nope if x[0] != 'F' or v[0] != 'V': return nope if v[1] not in x[2]: return nope # v must be free in x opd_push([ 'F', u'%s%s:%s' % (op, v[1], x[1]), x[2] - set([v[1]]), x[3] | set([v[1]]) ]) t2 = opd.pop() t1 = opd.pop() op = opr.pop() if opr.pop() != '<': return nope if op not in u'∧∨⊃': return nope if t1[0] != 'F' or t2[0] != 'F': return nope fv = (t1[2] | t2[2]) qv = (t1[3] | t2[3]) if (fv & qv): return nope opd_push(['F', u'<%s%s%s>' % (t1[1], op, t2[1]), fv, qv]) else: assert False while opr: if re.match('S+', opr_top()): op = opr.pop() t1 = opd.pop() if t1[0] != 'T': return nope opd_push(['T', op + t1[1], t1[2], set()]) elif opr_top() == '=': t2 = opd.pop() t1 = opd.pop() op = opr.pop() if t1[0] != 'T' or t2[0] != 'T': return nope opd_push( ['F', u'%s=%s' % (t1[1], t2[1]), t1[2] | t2[2], set()]) elif opr_top() == '~': t1 = opd.pop() assert opr.pop() == '~' if t1[0] != 'F': return nope opd_push(['F', u'~%s' % t1[1], t1[2], t1[3]]) elif opr_top() == ':': x = opd.pop() v = opd.pop() assert opr.pop() == ':' op = opr.pop() if op not in u'∀∃': return nope if x[0] != 'F' or v[0] != 'V': return nope if v[1] not in x[2]: return nope # v must be free in x opd_push([ 'F', u'%s%s:%s' % (op, v[1], x[1]), x[2] - set([v[1]]), x[3] | set([v[1]]) ]) else: return nope result = opd.pop() if opd: return nope if result[1] != s: print 'x is ', s print 'r is ', result[1] assert False return FormulaInfo(result[0] == 'F', result[2], result[3]) except IndexError: # Failed to pop something from one of the two stacks. return nope