def unifyWithOccursCheck(E1, E2, functionList, variableList, atomList): # check if empty List if checkIfEitherEmpty(E1, E2,): return unify(None,None,variableList) if checkIfValid(E1,functionList, variableList, atomList) or checkIfValid(E2,functionList, variableList, atomList): if E1 == E2: return unify(None,None,variableList) if str(E1) in variableList: if E1 in E2: #assignment will lead to infinite loop hence exit with occurs check error return exit("Violates Occurs Check ") else: return unify(E2, E1,variableList) if str(E2) in variableList: if E2 in E1: # assignment will lead to infinite loop hence exit with occurs check error return exit("Violates Occurs Check ") else: return unify(E1, E2,variableList) if not E1 in variableList and not E2 in variableList: return exit("Nope , cannot be unified!") # recusrisve funtion to get assignments SUBS1 = unifyWithOccursCheck(E1[0], E2[0], functionList, variableList, atomList) TE1 = SUBS1.unifyTerms(E1[1:]) TE2 = SUBS1.unifyTerms(E2[1:]) #recusrisve funtion to get assignments SUBS2 = unifyWithOccursCheck(TE1, TE2, functionList, variableList, atomList) return SUBS1.unifyTerms(SUBS2)
def resolve(rgoal, clause): rgoal = rgoal.copy() clause = clause.copy() if len(rgoal.get_terms()) > len(clause.get_terms()): return resolve(clause, rgoal) if not is_suitable(rgoal, clause): return False theta = Substitution() for goal_term in rgoal.get_terms(): op = goal_term.get_op() suitable_terms = clause.find_term_by_op(op) if suitable_terms == False: continue for suitable_term in suitable_terms: if goal_term.isNegative == suitable_term.isNegative: continue theta = Substitution() unify(goal_term, suitable_term, theta) if theta is not False: clause.remove(suitable_term) rgoal.remove(goal_term) break result = CNF(rgoal.get_terms() + clause.get_terms()) for term in result.terms: theta.SUBST(term) return result
def may_triggered(self, new_facts): # Check if any fact pi in new_facts is unified with a premise in rule for new_fact in new_facts: for premise in self.premises: if unify(new_fact, premise, Substitution()): return True return False
def forward(facts, kb): '''An exhaustive forward chaining algorithm for first-order definite clauses''' # each production is [antecedent_list, consequent_literal, triggers] stack = list(facts) productions = [[parse.antecedent(k), parse.consequent(k), []] for k in kb] entailed = [] while len(stack) > 0: current = stack.pop(0) for prod in productions: for ant in prod[0]: theta = unify.unify(current, ant) if theta != None: new_consequent = unify.subst(theta, prod[1]) new_triggers = prod[2] + [current] if len(prod[0]) == 1: # last one entailed.append([new_consequent, new_triggers]) stack.append(new_consequent) else: new_antecedent = list(prod[0]) new_antecedent.remove(ant) new_antecedent = [unify.subst(theta, x) for x in new_antecedent] productions.append([new_antecedent, new_consequent, new_triggers]) return entailed
def and_or_leaflists(remaining, indexed_kb, depth, antecedents = [], assumptions = []): '''Returns list of all entailing sets of leafs in the and-or backchaining tree''' if depth == 0 and len(antecedents) > 0: # fail return [] # (empty) list of lists elif len(remaining) == 0: # done with this level if len(antecedents) == 0: # found one return [assumptions] # list of lists else: return and_or_leaflists(antecedents, indexed_kb, depth - 1, [], assumptions) else: # more to go on this level literal = remaining[0] # first of remaining predicate = literal[0] if predicate not in indexed_kb: return and_or_leaflists(remaining[1:], indexed_kb, depth, antecedents, [literal] + assumptions) # shift literal to assumptions else: revisions = [] for rule in indexed_kb[predicate]: # indexed by predicate of literal theta = unify.unify(literal, parse.consequent(rule)) if theta != None: if depth == 0: # no depth for revision return [] # (empty) list of lists revisions.append([unify.subst(theta, remaining[1:]), # new remaining with substitutions indexed_kb, depth, unify.standardize(unify.subst(theta, parse.antecedent(rule))) + unify.subst(theta, antecedents), # new antecedents with substitutions unify.subst(theta, assumptions)]) # new assumptions with substitutions return itertools.chain(*[and_or_leaflists(*rev) for rev in revisions]) # list of lists (if any)
def contains( conj, lit): # where conj is the list of entailed, lit is an answer literal. for c in conj: if unify.unify(lit, c): return True return False
def run_unification(slices): # Executes the unification script with # the generated slice files (containing # line numbers). # Saves the output in the path specified # in global variables. if len(slices) < 1: return 1 check_and_remove(unification_output) raw_args = ["--file"] for slice in slices: raw_args.append(slice) raw_args.append(f"-o={unification_output}") unification_args = unify.parser.parse_args(raw_args) global created_files created_files.append(unification_output) return unify.unify(unification_args)
def resolve(query, kb): threshold = kb.size tbu = indexed_kb() query = cleanup_query(query) query[0]["truth"] = not query[0]["truth"] tbu.add(query, occur_check=True) iter = 0 #print query start = time.time() while not tbu.empty(): iter += 1 x, parent = tbu.pop() if not sanity_check(parent, kb, threshold): continue #print "Popped: ", x for x_pred in x: if not x_pred["truth"]: indices = get_indices(kb.true, x_pred["name"]) else: indices = get_indices(kb.false, x_pred["name"]) #print "X_pred is ", x_pred, indices for index in indices: y = kb.all[index] for y_pred in y: sub = unify(x_pred, y_pred) if sub is not None: resolved_sentence = get_resolved_sentence( copy.deepcopy(x), copy.deepcopy(y), copy.deepcopy(x_pred), copy.deepcopy(y_pred), sub) if resolved_sentence == []: return True if isTrue(resolved_sentence): return False resolved_sentence = standardize(resolved_sentence) new_parent = copy.deepcopy(parent) if index not in new_parent: new_parent[index] = 0 new_parent[index] += 1 tbu.add(resolved_sentence, new_parent, occur_check=True, verbose=False) print tbu.size, iter if len(resolved_sentence) > 10000: print "x: ", x print "y: ", y print "sub: ", sub print "Resolved: ", resolved_sentence print tbu.size print '\n' xxx = input() end = time.time() if (end - start) > 10: print "Breaking out in 10 seconds" break x = standardize(x) kb.add(x, occur_check=True) return False
def subst(facts_1, facts_2): # Generalized Modus Ponens if len(facts_1) != len(facts_2): return False for f1, f2 in zip(facts_1, facts_2): if f1.get_predicate() != f2.get_predicate(): return False return unify(facts_1, facts_2, Substitution())
def mergethetas(thetaset): '''Merge all substitutions into a single dictionary, or None if not consistent''' x = [] y = [] for theta in thetaset: for var in theta: x.append(var) y.append(theta[var]) return unify.unify(x, y)
def mergethetas(thetaset): '''Merge all substitutions into a single dictionary, or None if not consistent''' x = [] y = [] for theta in thetaset: for var in theta: x.append(var) y.append(theta[var]) return unify.unify(x,y)
def resolution(expr1, expr2): if expr1.name != expr2.name: return False, '' elif expr1.sign != 1 - expr2.sign: return False, '' else: sub = unify(expr1, expr2) if sub == 'Fail': return False, '' else: return True, sub
def fol_fc_ask(kb, alpha): res = set() while True: new_facts = set() for rule in KnowledgeBase.getRule(): count_premises = rule.count_premises() facts = kb.getFact() premises = itertools.permutations(facts, count_premises) for tuple_premises in premises: premises_ = [premise for premise in tuple_premises] theta = unify(rule.premise, premises_, Substitution()) if not theta: continue new_fact = rule.get_conclusion() theta.SUBST(new_fact) if new_fact not in new_facts and new_fact not in kb.getFact(): new_facts.add(new_fact) phi = unify(new_fact, alpha, Substitution()) if phi: if phi.empty(): for f in new_facts: kb.appendFact(f) res.add('true') return res res.add(phi) if not new_facts: if not res: res.add('false') return res for f in new_facts: kb.appendFact(f)
def crunch(conjunction): # returns a list of all possible ways to unify conjunction literals conjunction = [k for k,v in itertools.groupby(sorted(conjunction))] # remove duplicates res = [conjunction] # start with one solution pairs = itertools.combinations(conjunction, 2) thetas = [theta for theta in [unify.unify(p[0], p[1]) for p in pairs] if theta is not None] ps = powerset(thetas) for thetaset in ps: if len(thetaset) > 0: consistent = mergethetas(thetaset) if consistent: rewrite = [k for k,v in itertools.groupby(sorted(unify.subst(consistent, conjunction)))] if rewrite not in res: # expensive! res.append(rewrite) return res
def cruncher(conjunction, idx = 0): if idx >= len(conjunction) - 1: # last one return [[k for k,v in itertools.groupby(sorted(conjunction))]] # dedupe literals in solution else: res = [] for subsequent in range(idx + 1,len(conjunction)): theta = unify.unify(conjunction[idx], conjunction[subsequent]) if theta: new_conjunction = unify.subst(theta, conjunction[0:subsequent] + conjunction[(subsequent + 1):len(conjunction)]) res.extend(cruncher(new_conjunction, idx)) res.extend(cruncher(conjunction, idx + 1)) return res
def evaluate(solution, gold): # simpler, faster, permissive '''Calculates precision, recall, and f1 score of solution given gold-standard literals''' if len(solution) == 0: raise ValueError('The solution is zero-length') if len(gold) == 0: raise ValueError('The gold is zero-length') goldcount = float(len(gold)) solutioncount = float(len(solution)) unifiableInGold = 0.0 unifiableInSolution = 0.0 for sliteral in solution: for gliteral in gold: if unify.unify(sliteral, gliteral) != None: unifiableInSolution += 1.0 break; for gliteral in gold: for sliteral in solution: if unify.unify(sliteral, gliteral) != None: unifiableInGold += 1.0 break; # precision is unifiable in solution / solution count precision = unifiableInSolution / solutioncount # recall is unifiable in gold / gold count recall = unifiableInGold / goldcount # f1 is harmonic mean f1 = 2.0 * (precision * recall) / (precision + recall) print("goldcount", goldcount, "solutioncount", solutioncount, "unifiableInSolution", unifiableInSolution, "unifiableInGold", unifiableInGold, "precision", precision, "recall", recall, "f1", f1) return(precision, recall, f1)
def is_suitable(rgoal, clause): if len(rgoal.get_terms()) > len(clause.get_terms()): return is_suitable(clause, rgoal) for goal_term in rgoal.get_terms(): op = goal_term.get_op() suitable_terms = clause.find_term_by_op(op) if suitable_terms == False: continue else: for suitable_term in suitable_terms: if goal_term.isNegative == suitable_term.isNegative: continue else: theta = Substitution() if unify(goal_term, suitable_term, theta) is not False: return True return False
def successors(node): # node.state is a list of clauses, with the first one the current # clause def resolvent (parent1,parent2,lit1,lit2,uresult): both = parent1.cl + parent2.cl new = [] for b in both: if not b == lit1 and not b == lit2: newsentence = applySubs (b.sentence, uresult) new = new +[ Literal(b.neg,b.pred,newsentence)] new111 = Clause(new,[parent1.id,parent2.id]) return new111 succs = [] sos = []; #see if any clause in the current states sos can cancel out any other #clauses in the current KB for sos_clause in node.sos: #target is the clause in the KB being compared to sos_clause for target in node.state: #compare literals for lit1 in target.cl: for lit2 in sos_clause.cl: if not lit1.neg == lit2.neg and lit1.pred == lit2.pred: uresult = unify(lit1.sentence,lit2.sentence) if not uresult == 'fail': #resolve #create a new successor state and an updated sos for it new_clause = resolvent(sos_clause, target, lit1, lit2, uresult); new_sos = [new_clause] + node.sos; newsucc = [new_clause] + node.state; sos += [new_sos]; succs += [newsucc] #return a tuple of successor states paired with that states set of support return (succs, sos)
def crunch( conjunction ): # returns a list of all possible ways to unify conjunction literals conjunction = [k for k, v in itertools.groupby(sorted(conjunction)) ] # remove duplicates res = [conjunction] # start with one solution pairs = itertools.combinations(conjunction, 2) thetas = [ theta for theta in [unify.unify(p[0], p[1]) for p in pairs] if theta is not None ] ps = powerset(thetas) for thetaset in ps: if len(thetaset) > 0: consistent = mergethetas(thetaset) if consistent: rewrite = [ k for k, v in itertools.groupby( sorted(unify.subst(consistent, conjunction))) ] if rewrite not in res: # expensive! res.append(rewrite) return res
def unification(self, triple): if len(triple) == 3: t1 = triple[0] r = triple[1] t2 = triple[2] t1 = t1 if isvar(t1) else self.term.get_term_id(t1) r = r if isvar(r) else self.relation.get_relation_id(r) t2 = t2 if isvar(t2) else self.term.get_term_id(t2) generator = self.find(t1, r, t2) for item in generator: ans = unify(item, self.parse_triple_to_id(triple), {}) if isinstance(ans, dict): for key in ans.keys(): if 'T' in ans[key]: ans[key] = self.term.get_term_name(ans[key]) else: ans[key] = self.relation.get_relation_name(ans[key]) yield ans else: print triple, "unable to unify:", ans yield False else: yield False
def forward_chaining(kb, alpha): res = set() ## Check if alpha is proved in knowledge base for fact in kb.facts: phi = unify(fact, alpha, Substitution()) if phi: if phi.empty(): res.add('true') return res res.add(phi) last_generated_facts = kb.facts.copy() while True: new_facts = set() # Optimize: Incremental forward chaining # At iteration t, check a rule only if its premises includes at least # a conjunct pi that unified with the fact pi' newly inferred at iteration t - 1 for rule_predicate in kb.rules: rule = kb.get_rule(rule_predicate) if not rule.may_triggered(last_generated_facts): continue num_premises = rule.get_num_premises() # Get facts that relevant to the current rule potential_facts = kb.get_potential_facts(rule) # Check if rule contains premises with the same predicate if not rule.dup_predicate: potential_premises = itertools.combinations( sorted(potential_facts), num_premises) else: # Assumption on order of premises may failed on something like grandparent rule with two parent relations potential_premises = itertools.permutations( potential_facts, num_premises) for tuple_premises in potential_premises: fact_premises = [premise for premise in tuple_premises] # get a subtitution of kb.facts (relevant to rule) in rule premises theta = subst(rule.premises, fact_premises) if not theta: continue # subtitute theta to conclusion new_fact = rule.conclusion.copy() theta.substitute(new_fact) # if new fact is not a changed_name clause from a clause in kb if new_fact not in new_facts and new_fact not in kb.facts: new_facts.add(new_fact) # add new fact to fact list phi = unify( new_fact, alpha, Substitution()) # unify new_fact with the query if phi: # if is a "true" answer or a substitution if phi.empty(): kb.facts.update(new_facts) res.add('true') return res res.add(phi) last_generated_facts = new_facts if not new_facts: # if new_facts is an empty set if not res: # if res is an empty set too. This mean no satisfied substitution res.add('false') return res kb.facts.update(new_facts)
def backward_chaining(kb, alpha, theta): # check if alpha is empty if len(alpha) == 0: return theta # local variable to get answer answer = Substitution(); # pop a sub goal sub_goal = alpha.pop() # ********************************************************************* # if alpha is proved in knowledge base # check if alpha is a fact if sub_goal.predicate in kb.fact_predicate: # if theta set is include substitutions if len(theta) != 0: satisfy_element_index = [] sub_satisfied_theta_list = [] # substitute these substitution onto sub_goal k = 0 while k < len(theta): subst_value = theta[k] phi = sub_goal.copy() subst_value.substitute(phi) # check for if phi has a varialbe or not. Ex : "parent(X,harry_potter)." if utils.is_contain_variable(phi): for fact in kb.facts: sub_theta = unify(phi, fact, Substitution()) if not sub_theta: continue # if sub_theta is a successful substitution sub_phi = phi.copy() sub_theta.substitute(sub_phi) if sub_phi in kb.facts: if sub_theta not in sub_satisfied_theta_list: sub_satisfied_theta_list.append(sub_theta) k += 1 # else, phi is a fact to check true or false else: if phi in kb.facts: # if sub_goal is proven in kb, then return satisfy_element_index.append(k) k += 1 # add satisfied element with index in list if len(satisfy_element_index) != 0: new_theta = [] for i in satisfy_element_index: new_theta.append(theta[i]) # update theta theta = new_theta return backward_chaining(kb, alpha, theta) if len(sub_satisfied_theta_list) != 0: theta = sub_satisfied_theta_list return backward_chaining(kb, alpha, theta) # Pre-check if current facts are enough to answer/ find a substitution for sub_goal count = 0 for fact in kb.facts: phi = unify(fact, sub_goal, Substitution()) if phi: count += 1 if phi.empty(): # if sub_goal is proven in kb. There is no sub_goal adding. This sub_goal is done return backward_chaining(kb,alpha,theta) else: theta.append(phi) return backward_chaining(kb, alpha, theta) # ********************************************************************* # if alpha is a rule if sub_goal.predicate in kb.rule_conclusion_predicate: # get rule of sub_goal rule = kb.get_rule(sub_goal.predicate) num_premise = rule.get_num_premises() # get a list contains rule's premises premise_list = [] i = 0 while i < num_premise: premise_list.append(rule.premises[i]) i += 1 conclusion = rule.conclusion sub_theta = unify(conclusion, sub_goal, Substitution()) subs_value_for_premise = [] for premise in premise_list: temp_premise = premise.copy() sub_theta.substitute(temp_premise) subs_val = unify(premise, temp_premise, Substitution()) subs_value_for_premise.append(subs_val) i = 0 while i < len(premise_list): subs_val = subs_value_for_premise[i] premise = premise_list[i] subs_val.substitute(premise) alpha.append(premise) i += 1 return backward_chaining(kb, alpha, theta) #return res
def goal_eq(s): result = unify(u, v, s) if result is not False: yield result
def contextual_and_or_leaflists(remaining, indexed_kb, depth, context, antecedents=[], assumptions=[]): '''Returns list of all entailing sets of leafs in the and-or backchaining tree, with belief context''' if depth == 0 and len(antecedents) > 0: # fail return [] # (empty) list of lists elif len(remaining) == 0: # done with this level if len(antecedents) == 0: # found one return [assumptions] # list of lists else: return contextual_and_or_leaflists(antecedents, indexed_kb, depth - 1, context, [], assumptions) else: # more to go on this level literal = remaining[0] # first of remaining predicate = literal[0] if predicate not in indexed_kb: return contextual_and_or_leaflists( remaining[1:], indexed_kb, depth, context, antecedents, [literal] + assumptions) # shift literal to assumptions else: revisions = [] for rule in indexed_kb[ predicate]: # indexed by predicate of literal theta = unify.unify(literal, parse.consequent(rule)) if theta != None: if depth == 0: # no depth for revision return [] # (empty) list of lists revisions.append([ unify.subst( theta, remaining[1:]), # new remaining with substitutions indexed_kb, depth, context, unify.standardize( unify.subst(theta, parse.antecedent(rule))) + unify.subst( theta, antecedents), # new antecedents with substitutions unify.subst(theta, assumptions) ]) # new assumptions with substitutions for contextliteral in context: theta = unify.unify(literal, contextliteral) if theta != None: # literal unifies with context #print(str(literal) + " unifies with " + str(contextliteral) + " with theta " + str(theta) + " creating " + str(unify.subst(theta, literal))) revisions.append([ unify.subst( theta, remaining[1:]), # new remaining with substitutions indexed_kb, depth, context, # not revised unify.subst(theta, antecedents), # antecedents unify.subst(theta, assumptions) # assumptions ]) # should we "break" here now that we've found one? return itertools.chain(*[ contextual_and_or_leaflists(*rev) for rev in revisions ]) # list of lists (if any)
def contains(conj, lit): # where conj is the list of entailed, lit is an answer literal. for c in conj: if unify.unify(lit, c): return True return False
def forward_chaining(kb, alpha): res = set() # Pre-check if current facts are enough to answer for fact in kb.facts: phi = unify(fact, alpha, Substitution()) if phi: if phi.empty(): res.add('true') return res res.add(phi) last_generated_facts = kb.facts.copy() while True: new_facts = set() # Optimize: Incremental forward chaining # At iteration t, check a rule only if its premises includes at least # a conjunct pi that unified with the fact pi' newly inferred at iteration t - 1 for rule in kb.rules: if not rule.may_triggered(last_generated_facts): continue num_premises = rule.get_num_premises() # Get facts that relevant to the current rule potential_facts = kb.get_potential_facts(rule) # Check if rule contains premises with the same predicate if not rule.dup_predicate: potential_premises = itertools.combinations( sorted(potential_facts), num_premises) else: # Assumption on order of premises may failed on something like grandparent rule with two parent relations potential_premises = itertools.permutations( potential_facts, num_premises) for tuple_premises in potential_premises: premises = [premise for premise in tuple_premises] theta = subst(rule.premises, premises) if not theta: continue new_fact = rule.conclusion.copy() theta.substitute(new_fact) if new_fact not in new_facts and new_fact not in kb.facts: new_facts.add(new_fact) phi = unify(new_fact, alpha, Substitution()) if phi: if phi.empty(): kb.facts.update(new_facts) res.add('true') return res res.add(phi) last_generated_facts = new_facts if not new_facts: if not res: res.add('false') return res kb.facts.update(new_facts)