/// <summary> /// Returns empty list if the terms in the equation cannot be unified or if Lhs = Rhs with no variables, /// otherwise a list of substitutions defining the MGU /// /// Based on Unification chapter from Handbook of Automated Reasoning. /// </summary> private List<UnificationResult> GetMgu(Equation unificationProblem, List<TrsVariable> variableNamesToPreserve) { if (unificationProblem == null) throw new ArgumentException(); if (unificationProblem.Lhs == null) throw new ArgumentException(); if (unificationProblem.Rhs == null) throw new ArgumentException(); if (variableNamesToPreserve == null) throw new ArgumentException(); Equation initialEquation = unificationProblem.CreateCopy(); UnificationContinuation currentProblem = new UnificationContinuation { CurrentEquations = new List<Equation>(), CurrentSubstitutions = new List<Substitution>() }; currentProblem.CurrentEquations.Add(initialEquation); Queue<UnificationContinuation> currentContinuations = new Queue<UnificationContinuation>(); currentContinuations.Enqueue(currentProblem); HashSet<UnificationResult> results = new HashSet<UnificationResult>(); Func<UnificationContinuation, Equation, bool> processFail = delegate (UnificationContinuation curr, Equation currEq) { var failResult = CustomFail(currentProblem, currEq, variableNamesToPreserve); var succeed = true; if (failResult.Count == 0) succeed = false; else if (failResult.Count == 1) currentProblem = failResult.First(); else foreach (var continuation in failResult) currentContinuations.Enqueue(continuation); return succeed; }; while (currentContinuations.Count > 0) { currentProblem = currentContinuations.Dequeue(); bool fail = false; while (currentProblem.CurrentEquations.Count > 0 && !fail) { var currEq = currentProblem.CurrentEquations[currentProblem.CurrentEquations.Count - 1]; currentProblem.CurrentEquations.RemoveAt(currentProblem.CurrentEquations.Count - 1); if (currEq.Lhs.Equals(currEq.Rhs)) { // Elimination by omission (this is a "succeed" case) } else if (currEq.Lhs is TrsAtom && currEq.Rhs is TrsAtom) { if (!currEq.Lhs.Equals(currEq.Rhs)) { fail = !processFail(currentProblem, currEq); } } else if (currEq.Lhs is TrsAtom && currEq.Rhs is TrsTerm || currEq.Lhs is TrsTerm && currEq.Rhs is TrsAtom || currEq.Lhs is TrsAtom && currEq.Rhs is TrsAcTerm || currEq.Lhs is TrsAcTerm && currEq.Rhs is TrsAtom || currEq.Lhs is TrsTerm && currEq.Rhs is TrsAcTerm || currEq.Lhs is TrsAcTerm && currEq.Rhs is TrsTerm) { fail = !processFail(currentProblem, currEq); } else if (currEq.Lhs is TrsTerm && currEq.Rhs is TrsTerm) { TrsTerm lhs = currEq.Lhs as TrsTerm; TrsTerm rhs = currEq.Rhs as TrsTerm; if (lhs.Name != rhs.Name || lhs.Arguments.Count != rhs.Arguments.Count) fail = !processFail(currentProblem, currEq); else currentProblem.CurrentEquations.AddRange(Enumerable.Range(0, lhs.Arguments.Count). Select(i => new Equation { Lhs = lhs.Arguments[i], Rhs = rhs.Arguments[i] })); } else if (currEq.Lhs is TrsAcTerm && currEq.Rhs is TrsAcTerm) { // Note: Failure is already processed internally in the next function call (ie. custom unifiers are called) fail = ProcessAcUnificationStep(currentProblem, currentContinuations, processFail, currEq); } else if (!(currEq.Lhs is TrsVariable) && (currEq.Rhs is TrsVariable)) { TrsTermBase lhsSwap = currEq.Lhs; currEq.Lhs = currEq.Rhs; currEq.Rhs = lhsSwap; currentProblem.CurrentEquations.Add(currEq); } else if (currEq.Lhs is TrsVariable) { // Occurs check if (currEq.Rhs.ContainsVariable((TrsVariable)currEq.Lhs)) fail = !processFail(currentProblem, currEq); else ProcessSubstitutionStep(currentProblem, currEq, variableNamesToPreserve); } else throw new Exception("Invalid program state"); } if (!fail) results.Add(new UnificationResult { Succeed = true, Unifier = currentProblem.CurrentSubstitutions }); } return results.ToList(); }
/// <summary> /// Applies the custom unifiers for the current equation in case of failiure ... /// it applies the first working unifier from the list of custom unifiers. /// </summary> private List <UnificationContinuation> CustomFail(UnificationContinuation currentProblem, Equation currEq, List <TrsVariable> variableNamesToPreserve) { // First try custom unifiers ... use the first one that works. HashSet <UnificationResult> unificationResults = new HashSet <UnificationResult>(); foreach (var unifFunc in customUnifiers) { // Prevent overwriting of input terms ... var input = currEq.CreateCopy(); var unifiers = unifFunc.GetUnifier(input.Lhs, input.Rhs); if (unifiers != null) { foreach (var result in unifiers) { if (result.Succeed) { if (result.Unifier == null) { result.Unifier = new List <Substitution>(); } unificationResults.Add(result); } } } } unificationResults = new HashSet <UnificationResult>(unificationResults.Where(result => result.Succeed)); if (unificationResults.Count == 0) { return(new List <UnificationContinuation>()); } else { var retContinuations = new HashSet <UnificationContinuation>(); foreach (var customUnifier in unificationResults) { bool succeed = true; foreach (var customSubstitution in customUnifier.Unifier) { // Do occurs check if (customSubstitution.SubstitutionTerm.ContainsVariable(customSubstitution.Variable)) { succeed = false; break; } // Prevent conflicting mappings foreach (var substitution in currentProblem.CurrentSubstitutions) { if (substitution.Variable.Equals(customSubstitution.Variable) && !substitution.SubstitutionTerm.Equals(customSubstitution.SubstitutionTerm)) { succeed = false; break; } } } // Apply the subtitutions if (succeed) { // Create continuations here for injection back into the main algorithm loop UnificationContinuation currentContinuation = currentProblem.CreateCopy(); foreach (var substitution in customUnifier.Unifier) { ProcessSubstitutionStep(currentContinuation, new Equation { Lhs = substitution.Variable, Rhs = substitution.SubstitutionTerm }, variableNamesToPreserve); } retContinuations.Add(currentContinuation); } } return(retContinuations.ToList()); } }
/// <summary> /// Applies the custom unifiers for the current equation in case of failiure ... /// it applies the first working unifier from the list of custom unifiers. /// </summary> private List<UnificationContinuation> CustomFail(UnificationContinuation currentProblem, Equation currEq, List<TrsVariable> variableNamesToPreserve) { // First try custom unifiers ... use the first one that works. HashSet<UnificationResult> unificationResults = new HashSet<UnificationResult>(); foreach (var unifFunc in customUnifiers) { // Prevent overwriting of input terms ... var input = currEq.CreateCopy(); var unifiers = unifFunc.GetUnifier(input.Lhs, input.Rhs); if (unifiers != null) { foreach (var result in unifiers) if (result.Succeed) { if (result.Unifier == null) result.Unifier = new List<Substitution>(); unificationResults.Add(result); } } } unificationResults = new HashSet<UnificationResult>(unificationResults.Where(result => result.Succeed)); if (unificationResults.Count == 0) { return new List<UnificationContinuation>(); } else { var retContinuations = new HashSet<UnificationContinuation>(); foreach (var customUnifier in unificationResults) { bool succeed = true; foreach (var customSubstitution in customUnifier.Unifier) { // Do occurs check if (customSubstitution.SubstitutionTerm.ContainsVariable(customSubstitution.Variable)) { succeed = false; break; } // Prevent conflicting mappings foreach (var substitution in currentProblem.CurrentSubstitutions) { if (substitution.Variable.Equals(customSubstitution.Variable) && !substitution.SubstitutionTerm.Equals(customSubstitution.SubstitutionTerm)) { succeed = false; break; } } } // Apply the subtitutions if (succeed) { // Create continuations here for injection back into the main algorithm loop UnificationContinuation currentContinuation = currentProblem.CreateCopy(); foreach (var substitution in customUnifier.Unifier) ProcessSubstitutionStep(currentContinuation, new Equation { Lhs = substitution.Variable, Rhs = substitution.SubstitutionTerm }, variableNamesToPreserve); retContinuations.Add(currentContinuation); } } return retContinuations.ToList(); } }
/// <summary> /// Returns empty list if the terms in the equation cannot be unified or if Lhs = Rhs with no variables, /// otherwise a list of substitutions defining the MGU /// /// Based on Unification chapter from Handbook of Automated Reasoning. /// </summary> private List <UnificationResult> GetMgu(Equation unificationProblem, List <TrsVariable> variableNamesToPreserve) { if (unificationProblem == null) { throw new ArgumentException(); } if (unificationProblem.Lhs == null) { throw new ArgumentException(); } if (unificationProblem.Rhs == null) { throw new ArgumentException(); } if (variableNamesToPreserve == null) { throw new ArgumentException(); } Equation initialEquation = unificationProblem.CreateCopy(); UnificationContinuation currentProblem = new UnificationContinuation { CurrentEquations = new List <Equation>(), CurrentSubstitutions = new List <Substitution>() }; currentProblem.CurrentEquations.Add(initialEquation); Queue <UnificationContinuation> currentContinuations = new Queue <UnificationContinuation>(); currentContinuations.Enqueue(currentProblem); HashSet <UnificationResult> results = new HashSet <UnificationResult>(); Func <UnificationContinuation, Equation, bool> processFail = delegate(UnificationContinuation curr, Equation currEq) { var failResult = CustomFail(currentProblem, currEq, variableNamesToPreserve); var succeed = true; if (failResult.Count == 0) { succeed = false; } else if (failResult.Count == 1) { currentProblem = failResult.First(); } else { foreach (var continuation in failResult) { currentContinuations.Enqueue(continuation); } } return(succeed); }; while (currentContinuations.Count > 0) { currentProblem = currentContinuations.Dequeue(); bool fail = false; while (currentProblem.CurrentEquations.Count > 0 && !fail) { var currEq = currentProblem.CurrentEquations[currentProblem.CurrentEquations.Count - 1]; currentProblem.CurrentEquations.RemoveAt(currentProblem.CurrentEquations.Count - 1); if (currEq.Lhs.Equals(currEq.Rhs)) { // Elimination by omission (this is a "succeed" case) } else if (currEq.Lhs is TrsAtom && currEq.Rhs is TrsAtom) { if (!currEq.Lhs.Equals(currEq.Rhs)) { fail = !processFail(currentProblem, currEq); } } else if (currEq.Lhs is TrsAtom && currEq.Rhs is TrsTerm || currEq.Lhs is TrsTerm && currEq.Rhs is TrsAtom || currEq.Lhs is TrsAtom && currEq.Rhs is TrsAcTerm || currEq.Lhs is TrsAcTerm && currEq.Rhs is TrsAtom || currEq.Lhs is TrsTerm && currEq.Rhs is TrsAcTerm || currEq.Lhs is TrsAcTerm && currEq.Rhs is TrsTerm) { fail = !processFail(currentProblem, currEq); } else if (currEq.Lhs is TrsTerm && currEq.Rhs is TrsTerm) { TrsTerm lhs = currEq.Lhs as TrsTerm; TrsTerm rhs = currEq.Rhs as TrsTerm; if (lhs.Name != rhs.Name || lhs.Arguments.Count != rhs.Arguments.Count) { fail = !processFail(currentProblem, currEq); } else { currentProblem.CurrentEquations.AddRange(Enumerable.Range(0, lhs.Arguments.Count). Select(i => new Equation { Lhs = lhs.Arguments[i], Rhs = rhs.Arguments[i] })); } } else if (currEq.Lhs is TrsAcTerm && currEq.Rhs is TrsAcTerm) { // Note: Failure is already processed internally in the next function call (ie. custom unifiers are called) fail = ProcessAcUnificationStep(currentProblem, currentContinuations, processFail, currEq); } else if (!(currEq.Lhs is TrsVariable) && (currEq.Rhs is TrsVariable)) { TrsTermBase lhsSwap = currEq.Lhs; currEq.Lhs = currEq.Rhs; currEq.Rhs = lhsSwap; currentProblem.CurrentEquations.Add(currEq); } else if (currEq.Lhs is TrsVariable) { // Occurs check if (currEq.Rhs.ContainsVariable((TrsVariable)currEq.Lhs)) { fail = !processFail(currentProblem, currEq); } else { ProcessSubstitutionStep(currentProblem, currEq, variableNamesToPreserve); } } else { throw new Exception("Invalid program state"); } } if (!fail) { results.Add(new UnificationResult { Succeed = true, Unifier = currentProblem.CurrentSubstitutions }); } } return(results.ToList()); }