def coalesce(self, other): import logical.Connective as Connective if not isinstance(other, type(self)): raise ValueError( "Can't coalesce quantifiers of different types {} {}".format( repr(self), repr(other))) s = copy.deepcopy(self) o = copy.deepcopy(other) less, more = (s, o) if len(s.variables) < len(o.variables) else (o, s) translation = { old: new for old, new in zip(less.variables, more.variables) } less = less.rename(translation) terms = less.get_term() terms.extend(more.get_term()) if isinstance(self, Universal): ret = type(self)(more.variables, Connective.Conjunction(terms)) else: ret = type(self)(more.variables, Connective.Disjunction(terms)) return ret
def p_biconditional(p): """ biconditional : LPAREN IFF axiom axiom RPAREN """ p[0] = Connective.Conjunction([ Connective.Disjunction([Negation.Negation(p[3]), p[4]]), Connective.Disjunction([Negation.Negation(p[4]), p[3]]) ])
def __or__(self, other): ''' Operator overload for the '|' command, to simplify first-order logic operations. :return Connective.Disjunction() ''' import logical.Connective as Connective return Connective.Disjunction([self, other])
def push(self): ''' Push negation inwards and apply to all children ''' # Can be a conjunction or disjunction # Can be a single predicate # Can be a quantifier if isinstance(self.term(), Connective.Conjunction): ret = Connective.Disjunction([Negation(x) for x in self.term().get_term()]) elif isinstance(self.term(), Connective.Disjunction): ret = Connective.Conjunction([Negation(x) for x in self.term().get_term()]) elif isinstance(self.term(), Symbol.Predicate): ret = self elif isinstance(self.term(), Quantifier.Existential): ret = Quantifier.Universal(self.term().variables, Negation(self.term().get_term())) elif isinstance(self.term(), Quantifier.Universal): ret = Quantifier.Existential(self.term().variables, Negation(self.term().get_term())) elif isinstance(self.term(), Negation): ret = self.term().term() else: raise ValueError("Negation onto unknown type!", self.term) return copy.deepcopy(ret)
def substitute_function(self, negated = False): ''' Find a function that's nested and replace it by adding a new variable and term ''' # TODO This a dirty hack because cyclic imports are painful import logical.Quantifier as Quantifier import logical.Negation as Negation import logical.Connective as Connective global gen def sub_functions(term, predicates, variables): ''' Does three things: (1) returns a variable that serves as the placeholder for the function. (2) adds a minted predicate to the accumulator (3) adds any the newly introduced variable for each function to the accumulator ''' # Singleton used to access an increasing integer sequence global gen # Base Case 0: I'm not event a function, I'm a variable if isinstance(term, str): # I'm a variable so I go in the variable accumulator variables.append(term) return term # Base Case 1: I'm a function with no nested functions! if isinstance(term, Function) and term.has_functions() == False: # Mint a new variable special new_variable = term.name.lower()[0] + gen() variables.append(new_variable) # Mint a new predicate with our original variables + the new one predicate_variables = term.variables predicate_variables.append(new_variable) predicate = Predicate(term.name, predicate_variables) predicates.append(predicate) # Return our fresh variable return new_variable # Recursive Case: I'm a function with nested functions! if isinstance(term, Function): #and term.has_functions() == True: # Still mint a new variable cuz I'm still a function new_variable = term.name.lower()[0] + gen() variables.append(new_variable) # Assemble my variables by a DFS down on my function / atom children predicate_variables = [sub_functions(x, predicates, variables) for x in term.variables] predicate_variables.append(new_variable) predicate = Predicate(term.name, predicate_variables) predicates.append(predicate) return new_variable predicate_accumulator = [] variable_accumulator = [] variables = [sub_functions(x, predicate_accumulator, variable_accumulator) for x in self.variables] if len(predicate_accumulator) > 1: term = Connective.Conjunction(predicate_accumulator) else: term = predicate_accumulator.pop() predicate = Predicate(self.name, variables) if negated: # The negation cancels out the normal conditional breakdown universal = Quantifier.Universal(variable_accumulator, predicate | term) else: universal = Quantifier.Universal(variable_accumulator, ~predicate | term) return universal, predicate_accumulator
def p_conditional(p): """ conditional : LPAREN IF axiom axiom RPAREN """ p[0] = Connective.Disjunction([Negation.Negation(p[3]), p[4]])
def p_disjunction(p): """ disjunction : LPAREN OR axiom_list RPAREN """ p[0] = Connective.Disjunction(p[3])
def p_conjunction(p): """ conjunction : LPAREN AND axiom_list RPAREN """ p[0] = Connective.Conjunction(p[3])