Пример #1
0
        /// <summary>
        /// Combines a list of unifiers for the term product
        /// </summary>
        private UnificationResult ComposeUnifiers(IEnumerable <UnificationResult> unifierList)
        {
            if (unifierList.Count() == 1)
            {
                return(unifierList.First());
            }
            UnificationResult retVal = new UnificationResult();
            var composedUnifier      = new Dictionary <TrsVariable, TrsTermBase>();

            foreach (var unifier in unifierList)
            {
                foreach (var substitution in unifier.Unifier)
                {
                    TrsTermBase subValue = null;
                    if (!composedUnifier.TryGetValue(substitution.Variable, out subValue))
                    {
                        composedUnifier.Add(substitution.Variable, substitution.SubstitutionTerm);
                    }
                    else if (!subValue.Equals(substitution.SubstitutionTerm))
                    {
                        // Conflicting mapping found.
                        retVal.Succeed = false;
                        return(retVal);
                    }
                }
            }
            retVal.Succeed = true;
            retVal.Unifier = new List <Substitution>();
            retVal.Unifier.AddRange(composedUnifier.Select(pair => new Substitution
            {
                Variable         = pair.Key,
                SubstitutionTerm = pair.Value
            }));
            return(retVal);
        }
Пример #2
0
   public InterpreterEvaluationTerm(TrsTermBase root, TrsTermBase subterm, InterpreterTerm cacheSourceTerm, 
 UnificationResult currentUnifier)
       : base(root)
   {
       if (subterm == null) throw new ArgumentException("subterm");
         if (cacheSourceTerm == null) throw new ArgumentException("cacheSourceTerm");
         if (currentUnifier == null) throw new ArgumentException("currentUnifier");
         CurrentSubTerm = subterm;
         CacheSourceTerm = cacheSourceTerm;
         Unifier = currentUnifier;
   }
Пример #3
0
        public override bool Equals(object obj)
        {
            UnificationResult otherUnifier = obj as UnificationResult;

            if (otherUnifier == null)
            {
                return(false);
            }
            var substitutionSetOther = new HashSet <Substitution>(otherUnifier.Unifier);
            var subtitutionSetThis   = new HashSet <Substitution>(Unifier);

            substitutionSetOther.IntersectWith(subtitutionSetThis);
            return(Succeed == otherUnifier.Succeed &&
                   substitutionSetOther.Count == subtitutionSetThis.Count);
        }
Пример #4
0
 public InterpreterEvaluationTerm(TrsTermBase root, TrsTermBase subterm, InterpreterTerm cacheSourceTerm,
                                  UnificationResult currentUnifier)
     : base(root)
 {
     if (subterm == null)
     {
         throw new ArgumentException("subterm");
     }
     if (cacheSourceTerm == null)
     {
         throw new ArgumentException("cacheSourceTerm");
     }
     if (currentUnifier == null)
     {
         throw new ArgumentException("currentUnifier");
     }
     CurrentSubTerm  = subterm;
     CacheSourceTerm = cacheSourceTerm;
     Unifier         = currentUnifier;
 }
Пример #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);
        }
Пример #6
0
        private void ApplyReductionRuleToCache(TrsReductionRule rule)
        {
            // This data structure stores the Cartesian product used for term products
            // The length of each sub-List is the size of an alphabet for calculating a "Godel string" of terms.
            // This avoids the need for seperate sub-enumerators.
            var rewriteCandidates = new List <List <InterpreterEvaluationTerm> >();

            // Populate the rewriteCandidates
            TrsTermProduct ruleHead      = (TrsTermProduct)rule.Head;
            int            productLength = ruleHead.TermList.Count;

            for (int termProductIndex = 0; termProductIndex < productLength; termProductIndex++)
            {
                rewriteCandidates.Add(new List <InterpreterEvaluationTerm>());
                foreach (var termInCache in executionCache)
                {
                    // Do not rewrite new terms, we are doing one rewrite step at a time
                    if (termInCache.IsNewTerm)
                    {
                        continue;
                    }

                    // Test all sub-terms
                    var expantionStack = new Stack <TrsTermBase>();
                    expantionStack.Push(termInCache.RootTerm);
                    while (expantionStack.Count > 0)
                    {
                        var current = expantionStack.Pop();

                        // Ignore the "variable only" case to avoid matching all rewrite rules to a sub-term.
                        if (current is TrsVariable)
                        {
                            continue;
                        }

                        // Type rules applied here ... cater for multiple unification results by duplicating candidates
                        foreach (var unifier in mguCalculation.GetUnifier(ruleHead.TermList[termProductIndex], current))
                        {
                            if (IsUnifierValid(unifier, ruleHead.TermList[termProductIndex]))
                            {
                                rewriteCandidates[termProductIndex].Add(new InterpreterEvaluationTerm(termInCache.RootTerm, current, termInCache, unifier));
                            }
                        }

                        // Apply rewrite rule to subterms
                        if (current is TrsTerm)
                        {
                            foreach (var subTerm in ((TrsTerm)current).Arguments)
                            {
                                expantionStack.Push(subTerm);
                            }
                        }
                        else if (current is TrsAcTerm)
                        {
                            foreach (var subTerm in ((TrsAcTerm)current).OnfArguments)
                            {
                                expantionStack.Push(subTerm.Term);
                            }
                        }
                    }
                }
            }

            // Execute rewite step ... iterate over cartesian term product
            // This iterationCount variable will prevent rewriting in the case where any of the lists are empty
            int iterationCount = rewriteCandidates.First().Count;

            foreach (var termList in rewriteCandidates.Skip(1))
            {
                iterationCount *= termList.Count;
            }
            var matchTupple = new List <InterpreterEvaluationTerm>(rewriteCandidates.Count);

            for (int tuppleNumber = 0; tuppleNumber < iterationCount; tuppleNumber++)
            {
                var currDiv = tuppleNumber;
                UnificationResult currentUnifier = null;
                UnificationResult testUnifier    = null;
                matchTupple.Clear();
                // In order to do a substitution, all variables must bind to the same values across the tupple members
                for (int termColumn = 0; termColumn < rewriteCandidates.Count; termColumn++)
                {
                    var currMod = currDiv % rewriteCandidates[termColumn].Count;
                    currDiv = currDiv / rewriteCandidates[termColumn].Count;
                    var targetTerm = rewriteCandidates[termColumn][currMod];
                    currentUnifier = targetTerm.Unifier;
                    if (testUnifier == null)
                    {
                        testUnifier = currentUnifier;
                    }
                    matchTupple.Add(targetTerm);
                }
                var termProductUnifier = ComposeUnifiers(matchTupple.Select(term => term.Unifier));
                if (termProductUnifier.Succeed)
                {
                    foreach (var term in matchTupple)
                    {
                        ExecuteRewriteForRule(term, rule, termProductUnifier);
                    }
                }
            }
        }
Пример #7
0
        private void ExecuteRewriteForRule(InterpreterEvaluationTerm termToRewrite, TrsReductionRule rule, UnificationResult composedUnifier)
        {
            bool rewritingTookPlaceLocal = false;

            if (composedUnifier.Succeed)
            {
                if (rule.Tail.GetType() == typeof(TrsNativeKeyword))
                {
                    // Replacing term value with a native function generated value
                    var nativeTermInHead = ((TrsTermBase)termToRewrite.CurrentSubTerm.CreateCopy()).ApplySubstitutions(composedUnifier.Unifier);
                    foreach (var native in nativeFunctions)
                    {
                        var processedTerm = native.Evaluate(nativeTermInHead);
                        if (processedTerm == null)
                        {
                            throw new Exception(string.Format("Native function in type {0} returned null", native.GetType().FullName));
                        }
                        // If the rewrite result is the same, no rewriting took place ...
                        if (!nativeTermInHead.Equals(processedTerm))
                        {
                            var newTerm = termToRewrite.RootTerm.CreateCopyAndReplaceSubTerm(termToRewrite.CurrentSubTerm, processedTerm);
                            rewritingTookPlaceLocal = true;
                            var newTermWrapper = new InterpreterTerm(newTerm);
                            newTermWrapper.IsNewTerm = true;
                            executionCache.Add(newTermWrapper);
                        }
                    }
                }
                else
                {
                    // Normal rewriting without native eval functions
                    var replacementTerm = ((TrsTermBase)rule.Tail.CreateCopy()).ApplySubstitutions(composedUnifier.Unifier);
                    if (!termToRewrite.CurrentSubTerm.Equals(replacementTerm))
                    {
                        var newTerm = termToRewrite.RootTerm.CreateCopyAndReplaceSubTerm(termToRewrite.CurrentSubTerm, replacementTerm);
                        rewritingTookPlaceLocal = true;
                        var newTermWrapper = new InterpreterTerm(newTerm);
                        newTermWrapper.IsNewTerm = true;
                        executionCache.Add(newTermWrapper);
                    }
                }
            }
            if (rewritingTookPlaceLocal)
            {
                rewritingTookPlace = true; // stops rewriting on next rewrite step
                termToRewrite.CacheSourceTerm.MustDeletFromCache = true;
            }
        }
Пример #8
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;
        }
Пример #9
0
 private void ExecuteRewriteForRule(InterpreterEvaluationTerm termToRewrite, TrsReductionRule rule, UnificationResult composedUnifier)
 {
     bool rewritingTookPlaceLocal = false;
       if (composedUnifier.Succeed)
       {
     if (rule.Tail.GetType() == typeof(TrsNativeKeyword))
     {
       // Replacing term value with a native function generated value
       var nativeTermInHead = ((TrsTermBase)termToRewrite.CurrentSubTerm.CreateCopy()).ApplySubstitutions(composedUnifier.Unifier);
       foreach (var native in nativeFunctions)
       {
     var processedTerm = native.Evaluate(nativeTermInHead);
     if (processedTerm == null) throw new Exception(string.Format("Native function in type {0} returned null", native.GetType().FullName));
     // If the rewrite result is the same, no rewriting took place ...
     if (!nativeTermInHead.Equals(processedTerm))
     {
       var newTerm = termToRewrite.RootTerm.CreateCopyAndReplaceSubTerm(termToRewrite.CurrentSubTerm, processedTerm);
       rewritingTookPlaceLocal = true;
       var newTermWrapper = new InterpreterTerm(newTerm);
       newTermWrapper.IsNewTerm = true;
       executionCache.Add(newTermWrapper);
     }
       }
     }
     else
     {
       // Normal rewriting without native eval functions
       var replacementTerm = ((TrsTermBase)rule.Tail.CreateCopy()).ApplySubstitutions(composedUnifier.Unifier);
       if (!termToRewrite.CurrentSubTerm.Equals(replacementTerm))
       {
     var newTerm = termToRewrite.RootTerm.CreateCopyAndReplaceSubTerm(termToRewrite.CurrentSubTerm, replacementTerm);
     rewritingTookPlaceLocal = true;
     var newTermWrapper = new InterpreterTerm(newTerm);
     newTermWrapper.IsNewTerm = true;
     executionCache.Add(newTermWrapper);
       }
     }
       }
       if (rewritingTookPlaceLocal)
       {
     rewritingTookPlace = true; // stops rewriting on next rewrite step
     termToRewrite.CacheSourceTerm.MustDeletFromCache = true;
       }
 }
Пример #10
0
 /// <summary>
 /// Combines a list of unifiers for the term product
 /// </summary>
 private UnificationResult ComposeUnifiers(IEnumerable<UnificationResult> unifierList)
 {
     if (unifierList.Count() == 1) return unifierList.First();
       UnificationResult retVal = new UnificationResult();
       var composedUnifier = new Dictionary<TrsVariable, TrsTermBase>();
       foreach (var unifier in unifierList)
       {
     foreach (var substitution in unifier.Unifier)
     {
       TrsTermBase subValue = null;
       if (!composedUnifier.TryGetValue(substitution.Variable, out subValue))
       {
     composedUnifier.Add(substitution.Variable, substitution.SubstitutionTerm);
       }
       else if (!subValue.Equals(substitution.SubstitutionTerm))
       {
     // Conflicting mapping found.
     retVal.Succeed = false;
     return retVal;
       }
     }
       }
       retVal.Succeed = true;
       retVal.Unifier = new List<Substitution>();
       retVal.Unifier.AddRange(composedUnifier.Select(pair => new Substitution
       {
     Variable = pair.Key,
     SubstitutionTerm = pair.Value
       }));
       return retVal;
 }
Пример #11
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 };
        }