Beispiel #1
0
        public override bool Equals(object obj)
        {
            Substitution other = obj as Substitution;

            return(other != null &&
                   Variable.Equals(other.Variable) &&
                   SubstitutionTerm.Equals(other.SubstitutionTerm));
        }
        /// <summary>
        /// Adds the given substitution to the existing oners and apply the new composition
        /// to the existing problem.
        /// </summary>
        public void ComposeAndApplySubstitutions(Substitution newSubstitution)
        {
            // Add the new substitution to the existing ones
              List<Substitution> removeList = new List<Substitution>();
              bool found = false;
              foreach (var sub in CurrentSubstitutions)
              {
            sub.SubstitutionTerm = sub.SubstitutionTerm.ApplySubstitutions(new[] { newSubstitution });
            if (sub.Variable.Equals(sub.SubstitutionTerm)) removeList.Add(sub);
            else found = sub.Variable.Equals(newSubstitution.Variable);
              }
              CurrentSubstitutions.RemoveAll(r => removeList.Contains(r));
              if (!found) CurrentSubstitutions.Add(newSubstitution);

              // Apply the modified substitutions to the existing problem
              foreach (var eq in CurrentEquations)
              {
            eq.Lhs = eq.Lhs.ApplySubstitutions(CurrentSubstitutions);
            eq.Rhs = eq.Rhs.ApplySubstitutions(CurrentSubstitutions);
              }
        }
Beispiel #3
0
        /// <summary>
        /// Uses the input type definitions as a bottom up tree automaton to
        /// test the input mapping of a variable to a term.
        ///
        /// Note:
        /// * All final states must be matched for a mapping to be valid.
        /// * Types are "merged" therefore the same type definition name can have multiple definitions associated.
        /// </summary>
        public bool IsSubstitutionValid(Substitution substitution)
        {
            HashSet <TrsTypeDefinitionTypeName> endStates = null;

            // If variable not bound, it is valid by default
            if (!typeMappings.TryGetValue(substitution.Variable, out endStates))
            {
                return(true);
            }

            // Initial and final states
            var termIn = substitution.SubstitutionTerm.Convert();

            AddDynamicStates(termIn);

            InterpreterType testType = new InterpreterType(termIn);
            var             retVal   = testType.IsTermValid(transitionFunction, endStates);

            // Undo dynamic changes to state machine to cater for $TrsNumber, $TrsConstant, $TrsString and $TrsVariable
            RemoveDynamicStates();

            return(retVal);
        }
Beispiel #4
0
        private void ProcessSubstitutionStep(UnificationContinuation currentProblem, Equation currEq, List <TrsVariable> variableNamesToPreserve)
        {
            // LHS will always be variable here ... preserve matched term variables
            Substitution newSub = null;

            if (currEq.Rhs is TrsVariable &&
                variableNamesToPreserve.Contains(currEq.Lhs))
            {
                newSub = new Substitution
                {
                    Variable         = (TrsVariable)currEq.Rhs,
                    SubstitutionTerm = currEq.Lhs
                };
            }
            else
            {
                newSub = new Substitution
                {
                    Variable         = (TrsVariable)currEq.Lhs,
                    SubstitutionTerm = currEq.Rhs
                };
            }
            currentProblem.ComposeAndApplySubstitutions(newSub);
        }
Beispiel #5
0
        /// <summary>
        /// Checks that the given unifier is valid in terms of the type definitions.
        /// </summary>
        private bool IsUnifierValid(UnificationResult unifier, TrsTermBase matchedRuleHead)
        {
            // Variables at this level must be validated in a way that is sensitive to AC term type definitions
            // to account for semantics. If it is not add[:x,:y] will not match add[1,2,3] with limit :x,:y to $TrsNumber
            if (!unifier.Succeed)
            {
                return(false);
            }
            if (unifier.Unifier.Count == 0)
            {
                return(true);                      // equal terms, nothing to validate
            }
            // Keep track of variable parent cases
            Stack <TrsTermBase>            evalStack     = new Stack <TrsTermBase>();
            Dictionary <TrsVariable, bool> isAcParent    = new Dictionary <TrsVariable, bool>();
            Dictionary <TrsVariable, bool> isNonAcParent = new Dictionary <TrsVariable, bool>();
            Dictionary <TrsVariable, HashSet <string> > variableTermNames = new Dictionary <TrsVariable, HashSet <string> >();

            evalStack.Push(matchedRuleHead);
            Action <TrsVariable, bool, Dictionary <TrsVariable, bool> > updateLookups =
                delegate(TrsVariable v, bool b, Dictionary <TrsVariable, bool> target)
            {
                if (target.ContainsKey(v))
                {
                    target[v] = b;
                }
                else
                {
                    target.Add(v, b);
                }
            };

            while (evalStack.Count > 0)
            {
                var current = evalStack.Pop();
                // Variable only case ... this should not happen unless variable only reduction rule heads are allowed in the future
                var currentVariable = current as TrsVariable;
                if (currentVariable != null)
                {
                    updateLookups(currentVariable, false, isAcParent);
                    updateLookups(currentVariable, false, isNonAcParent);
                }
                else
                {
                    // Check arguments
                    var curTerm   = current as TrsTerm;
                    var curAcTerm = current as TrsAcTerm;
                    foreach (var variable in Enumerable.Concat(curTerm == null ? new TrsVariable[0] : curTerm.Arguments.Where(arg => arg is TrsVariable).Cast <TrsVariable>(),
                                                               curAcTerm == null ? new TrsVariable[0] : curAcTerm.OnfArguments.Where(arg => arg.Term is TrsVariable).Select(arg => arg.Term).Cast <TrsVariable>()))
                    {
                        updateLookups(variable, curTerm != null, isNonAcParent);
                        updateLookups(variable, curAcTerm != null, isAcParent);
                        if (curAcTerm != null)
                        {
                            HashSet <string> termNames;
                            if (!variableTermNames.TryGetValue(variable, out termNames))
                            {
                                variableTermNames.Add(variable, termNames = new HashSet <string>());
                            }
                            termNames.Add(curAcTerm.Name);
                        }
                    }
                }
            }

            bool isValid = true;

            foreach (var substitution in unifier.Unifier)
            {
                // It is possible that the variable being tested does not occur in the term head ...
                if (!isNonAcParent.ContainsKey(substitution.Variable) &&
                    !isAcParent.ContainsKey(substitution.Variable))
                {
                    isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
                    continue;
                }

                // AC term case
                if (isNonAcParent.ContainsKey(substitution.Variable) &&
                    isNonAcParent[substitution.Variable])
                {
                    isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
                }

                // Non-AC term case
                if (isAcParent.ContainsKey(substitution.Variable) &&
                    isAcParent[substitution.Variable])
                {
                    var acSubstitutionTerm = substitution.SubstitutionTerm as TrsAcTerm;
                    if (acSubstitutionTerm == null ||
                        !variableTermNames[substitution.Variable].Contains(acSubstitutionTerm.Name))
                    {
                        isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
                    }
                    else
                    {
                        // In this case, test each nested argument of the AC substitution term to match the term head variable.
                        // This is due to the ONF convertion for AC terms. It keeps type checking in line with AC semantics.
                        foreach (var argTerm in acSubstitutionTerm.OnfArguments.Select(arg => arg.Term))
                        {
                            var testSubstitution = new Substitution {
                                Variable = substitution.Variable, SubstitutionTerm = argTerm
                            };
                            isValid = isValid && typeChecker.IsSubstitutionValid(testSubstitution);
                        }
                    }
                }
            }
            return(isValid);
        }
Beispiel #6
0
 /// <summary>
 /// Applies the given substituion to this term, creating a new term. This method is used by the public
 /// version to apply a collection of substitutions.
 /// </summary>
 protected abstract TrsTermBase ApplySubstitution(Substitution substitution);
Beispiel #7
0
        /// <summary>
        /// Checks that the given unifier is valid in terms of the type definitions.
        /// </summary>
        private bool IsUnifierValid(UnificationResult unifier, TrsTermBase matchedRuleHead)
        {
            // Variables at this level must be validated in a way that is sensitive to AC term type definitions
              // to account for semantics. If it is not add[:x,:y] will not match add[1,2,3] with limit :x,:y to $TrsNumber
              if (!unifier.Succeed) return false;
              if (unifier.Unifier.Count == 0) return true; // equal terms, nothing to validate

              // Keep track of variable parent cases
              Stack<TrsTermBase> evalStack = new Stack<TrsTermBase>();
              Dictionary<TrsVariable, bool> isAcParent = new Dictionary<TrsVariable, bool>();
              Dictionary<TrsVariable, bool> isNonAcParent = new Dictionary<TrsVariable, bool>();
              Dictionary<TrsVariable, HashSet<string>> variableTermNames = new Dictionary<TrsVariable, HashSet<string>>();

              evalStack.Push(matchedRuleHead);
              Action<TrsVariable, bool, Dictionary<TrsVariable, bool>> updateLookups =
            delegate(TrsVariable v, bool b, Dictionary<TrsVariable, bool> target)
            {
              if (target.ContainsKey(v)) target[v] = b;
              else target.Add(v, b);
            };
              while (evalStack.Count > 0)
              {
            var current = evalStack.Pop();
            // Variable only case ... this should not happen unless variable only reduction rule heads are allowed in the future
            var currentVariable = current as TrsVariable;
            if (currentVariable != null)
            {
              updateLookups(currentVariable, false, isAcParent);
              updateLookups(currentVariable, false, isNonAcParent);
            }
            else
            {
              // Check arguments
              var curTerm = current as TrsTerm;
              var curAcTerm = current as TrsAcTerm;
              foreach (var variable in Enumerable.Concat(curTerm == null ? new TrsVariable[0] : curTerm.Arguments.Where(arg => arg is TrsVariable).Cast<TrsVariable>(),
            curAcTerm == null ? new TrsVariable[0] : curAcTerm.OnfArguments.Where(arg => arg.Term is TrsVariable).Select(arg => arg.Term).Cast<TrsVariable>()))
              {
            updateLookups(variable, curTerm != null, isNonAcParent);
            updateLookups(variable, curAcTerm != null, isAcParent);
            if (curAcTerm != null)
            {
              HashSet<string> termNames;
              if (!variableTermNames.TryGetValue(variable, out termNames))
                variableTermNames.Add(variable, termNames = new HashSet<string>());
              termNames.Add(curAcTerm.Name);
            }
              }
            }
              }

              bool isValid = true;
              foreach (var substitution in unifier.Unifier)
              {
            // It is possible that the variable being tested does not occur in the term head ...
            if (!isNonAcParent.ContainsKey(substitution.Variable)
              && !isAcParent.ContainsKey(substitution.Variable))
            {
              isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
              continue;
            }

            // AC term case
            if (isNonAcParent.ContainsKey(substitution.Variable) &&
              isNonAcParent[substitution.Variable])
              isValid = isValid && typeChecker.IsSubstitutionValid(substitution);

            // Non-AC term case
            if (isAcParent.ContainsKey(substitution.Variable)
              && isAcParent[substitution.Variable])
            {
              var acSubstitutionTerm = substitution.SubstitutionTerm as TrsAcTerm;
              if (acSubstitutionTerm == null
            || !variableTermNames[substitution.Variable].Contains(acSubstitutionTerm.Name))
              {
            isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
              }
              else
              {
            // In this case, test each nested argument of the AC substitution term to match the term head variable.
            // This is due to the ONF convertion for AC terms. It keeps type checking in line with AC semantics.
            foreach (var argTerm in acSubstitutionTerm.OnfArguments.Select(arg => arg.Term))
            {
              var testSubstitution = new Substitution { Variable = substitution.Variable, SubstitutionTerm = argTerm };
              isValid = isValid && typeChecker.IsSubstitutionValid(testSubstitution);
            }
              }
            }
              }
              return isValid;
        }
Beispiel #8
0
        /// <summary>
        /// NB: this is not a general solution, only for c = b + x where + can be -, / or * and, b and x can be swapped arround.
        /// c is the match term. The rest is the head term. 
        /// </summary>
        public List<UnificationResult> GetUnifier(TrsTermBase termHead, TrsTermBase matchTerm)
        {
            UnificationResult result = new UnificationResult();
              result.Succeed = false;

              // Check input
              Substitution sRhs = new Substitution
              {
            Variable = new TrsVariable("exp_r"),
            SubstitutionTerm = termHead
              };
              Substitution sLhs = new Substitution
              {
            Variable = new TrsVariable("exp_l"),
            SubstitutionTerm = matchTerm
              };
              var headTerm = termHead as TrsTerm;
              if (!interpreter.TypeChecker.IsSubstitutionValid(sLhs) ||
            !interpreter.TypeChecker.IsSubstitutionValid(sRhs))
              {
            return new List<UnificationResult> { result };
              }

              // Load problem
              interpreter.ClearExecutionCache();
              interpreter.LoadTerms(new []
              {
            new TrsTerm("rhs",new [] { termHead }),
            new TrsTerm("lhs",new [] { matchTerm })
              });

              // Solve
              while (interpreter.ExecuteRewriteStep()) { };

              // Extract answer
              var runResults = interpreter.GetCurrentRewriteResult();
              foreach (var stm in runResults.ProgramOut.Statements)
              {
            var resEq = stm as TrsTerm;
            if (resEq != null
              && resEq.Name == "eq"
              && resEq.Arguments.Count == 2
              && resEq.Arguments[0] is TrsNumber
              && resEq.Arguments[1] is TrsVariable)
            {
              result.Succeed = true;
              result.Unifier = new List<Substitution>();
              result.Unifier.Add(new Substitution()
              {
            Variable = resEq.Arguments[1] as TrsVariable,
            SubstitutionTerm = resEq.Arguments[0]
              });
            }
              }
              return new List<UnificationResult> { result };
        }
Beispiel #9
0
 private void ProcessSubstitutionStep(UnificationContinuation currentProblem, Equation currEq, List<TrsVariable> variableNamesToPreserve)
 {
     // LHS will always be variable here ... preserve matched term variables
       Substitution newSub = null;
       if (currEq.Rhs is TrsVariable
     && variableNamesToPreserve.Contains(currEq.Lhs))
       {
     newSub = new Substitution
     {
       Variable = (TrsVariable)currEq.Rhs,
       SubstitutionTerm = currEq.Lhs
     };
       }
       else
       {
     newSub = new Substitution
     {
       Variable = (TrsVariable)currEq.Lhs,
       SubstitutionTerm = currEq.Rhs
     };
       }
       currentProblem.ComposeAndApplySubstitutions(newSub);
 }
Beispiel #10
0
 protected override TrsTermBase ApplySubstitution(Substitution substitution)
 {
     TrsTermProduct product = new TrsTermProduct(new List<TrsTermBase>());
       foreach (var term in TermList)
       {
     if (term.Equals(substitution.Variable)) product.TermList.Add(substitution.SubstitutionTerm);
     else product.TermList.Add(term.ApplySubstitutions(new [] { substitution }));
       }
       return product;
 }
Beispiel #11
0
 protected override TrsTermBase ApplySubstitution(Substitution substitution)
 {
     return this;
 }
Beispiel #12
0
        /// <summary>
        /// Uses the input type definitions as a bottom up tree automaton to 
        /// test the input mapping of a variable to a term.
        /// 
        /// Note: 
        /// * All final states must be matched for a mapping to be valid.
        /// * Types are "merged" therefore the same type definition name can have multiple definitions associated.
        /// </summary>
        public bool IsSubstitutionValid(Substitution substitution)
        {
            HashSet<TrsTypeDefinitionTypeName> endStates = null;

              // If variable not bound, it is valid by default
              if (!typeMappings.TryGetValue(substitution.Variable, out endStates)) return true;

              // Initial and final states
              var termIn = substitution.SubstitutionTerm.Convert();
              AddDynamicStates(termIn);

              InterpreterType testType = new InterpreterType(termIn);
              var retVal = testType.IsTermValid(transitionFunction, endStates);

              // Undo dynamic changes to state machine to cater for $TrsNumber, $TrsConstant, $TrsString and $TrsVariable
              RemoveDynamicStates();

              return retVal;
        }