/// <summary> /// Creates new substitutions and applies them to the current substitutions and equations to eliminate existing variables. /// </summary> /// <returns>True is succeed, false if a value clash occurs (ie. the same variable mapped to different values.)</returns> private bool CreateAndUpdateSubstitutions(Equation next, List <Substitution> substitutions, Queue <Equation> currentEquations) { // Check if same variable would be mapped to different values foreach (var substitution in substitutions) { // Test for a mapping clash if (next.Lhs == substitution.MatchTerm && // same name next.Rhs != substitution.SubstituteTerm) // different values { return(false); } } // Create the new substitution var newSubstitution = new Substitution { MatchTerm = next.Lhs, SubstituteTerm = next.Rhs }; // Apply new substitution to current substitutions to eleminate the variable and in the process solve it foreach (var substitution in substitutions) { substitution.SubstituteTerm = ApplySubstitution(newSubstitution, substitution.SubstituteTerm); } substitutions.Add(newSubstitution); // Remove all cases where a variable now maps to itself ... // this could potentially cause a "fail" to to mappings clashes later on substitutions.RemoveAll(s => s.MatchTerm == s.SubstituteTerm); // Apply new substitution to current equations to eleminate variable and in the process "solve" it foreach (var eq in currentEquations) { eq.Lhs = ApplySubstitution(newSubstitution, eq.Lhs); eq.Rhs = ApplySubstitution(newSubstitution, eq.Rhs); } return(true); }
/// <summary> /// Calculates a unifier for the terms in the input equation. /// </summary> /// <param name="unificationProblem">Gives the two terms that have to be unified.</param> /// <param name="storage">Database associated with the terms in the unification problem.</param> /// <returns>Substitutuions for variables and a boolean indicating whether unification succeeded.</returns> public (IEnumerable <Substitution> substitutions, bool succeed) GetSyntacticUnifier(Equation unificationProblem) { // See Franz Baader and Wayne Snyder (2001). "Unification Theory". In John Alan Robinson and Andrei Voronkov, // editors, Handbook of Automated Reasoning, volume I, pages 447–533. Elsevier Science Publishers. if (unificationProblem.Lhs.Name.TermIdentifier.Value == unificationProblem.Rhs.Name.TermIdentifier.Value) { return(Enumerable.Empty <Substitution>(), true); } var substitutions = new List <Substitution>(); var currentEquations = new Queue <Equation>(); currentEquations.Enqueue(unificationProblem); while (currentEquations.Any()) { var next = currentEquations.Dequeue(); Term lhs = next.Lhs; Term rhs = next.Rhs; // NB: Do not change the sequence of operations in this loop // "Trivial" case - LHS equals RHS if (lhs.Name.TermIdentifier.Value == rhs.Name.TermIdentifier.Value) { continue; } // Symbol clash - Fail case if (lhs.Name.Type != SymbolType.Variable && rhs.Name.Type != SymbolType.Variable && ( lhs.Name.Type != rhs.Name.Type || !NameEquals(lhs, rhs) || lhs.Arguments.Length != rhs.Arguments.Length ) ) { return(Enumerable.Empty <Substitution>(), false); } // Orient - No need to enqueue it at this point, next rules will process it if (lhs.Name.Type != SymbolType.Variable && rhs.Name.Type == SymbolType.Variable) { var temp = lhs; next.Lhs = next.Rhs; next.Rhs = temp; currentEquations.Enqueue(next); continue; } // Occurs check - The case where LHS = RHS and LHS is variable already covered under "Trivial" case if (lhs.Name.Type == SymbolType.Variable && rhs.Variables.Contains(lhs)) { return(Enumerable.Empty <Substitution>(), false); } // Variable elimination if (lhs.Name.Type == SymbolType.Variable) { if (!CreateAndUpdateSubstitutions(next, substitutions, currentEquations)) { // Fail: same variable mapped to different values return(Enumerable.Empty <Substitution>(), false); } } // Decomposition if (lhs.Name.Type == SymbolType.NonAcTerm || lhs.Name.Type == SymbolType.TermList) { for (int i = 0; i < lhs.Arguments.Length; i++) { currentEquations.Enqueue(new Equation { Lhs = lhs.Arguments[i], Rhs = rhs.Arguments[i] }); } } } return(substitutions, true); }