def apply_substitution_to_term(term: Term, substitution: Dict[str, Term]) -> Term: complete_substitution = {} # NOTE: all variables in the term need to be defined in the substitution for var in term.variables(): complete_substitution[var.name] = Var(var.name) complete_substitution.update(substitution) term_substitution = term.apply(complete_substitution) return term_substitution
def unify_value_different_contexts(value1: Term, value2: Term, source_values, target_values): """ Unify two values that exist in different contexts. Updates the mapping of variables from value1 to values from value2. :param value1: :param value2: :param source_values: mapping of source variable to target value :param target_values: mapping of target variable to TARGET value """ # Variables are negative numbers or None if is_variable(value1) and is_variable(value2): if value1 is None: # value1 is anonyous var pass elif value2 is None: # value2 is anonymous pass else: # Two named variables # Check whether value2 is already linked to another value in the target context sv2 = target_values.get(value2, value2) if sv2 == value2: # no # Check whether value1 is already linked to a value sv1 = source_values.get(value1) if sv1 is None: # no # We can link variable 1 with variable 2 source_values[value1] = value2 else: # yes: we need to unify sv1 and value2 (they both are in target scope) unify_value(sv1, value2, target_values) else: # value2 is already linked to another value # we need to unify value1 with that value unify_value_different_contexts(value1, sv2, source_values, target_values) # only value1 is a variable; value2 is a nonvar term elif is_variable(value1): if value1 is None: pass else: sv1 = source_values.get(value1) if sv1 is None: source_values[value1] = value2 elif is_variable(sv1): if sv1 in value2.variables(): raise OccursCheck() if sv1 != value2: target_values[sv1] = value2 source_values[value1] = value2 else: # unify in same context target_values source_values[value1] = unify_value(source_values[value1], value2, target_values) # only value2 is a variable; value1 is a nonvar term elif is_variable(value2): sv2 = target_values.get(value2) if sv2 is None: target_values[value2] = value1.apply(source_values) elif is_variable(sv2): pass else: unify_value_different_contexts(value1, sv2, source_values, target_values) # value1 and value2 are both not variables # but they are terms with the same signature elif value1.signature == value2.signature: # Assume Term for a1, a2 in zip(value1.args, value2.args): unify_value_different_contexts(a1, a2, source_values, target_values) # they don't have the same signature else: raise UnifyError()