コード例 #1
0
ファイル: Interpreter.cs プロジェクト: sadeslandes/TRL
        /// <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 static TrsTypeDefinitionTermBase Convert(this TrsTermBase termIn)
        {
            TrsAtom     atom     = termIn as TrsAtom;
            TrsVariable variable = termIn as TrsVariable;
            TrsTerm     term     = termIn as TrsTerm;
            TrsAcTerm   acTerm   = termIn as TrsAcTerm;

            if (atom != null)
            {
                return(atom.Convert());
            }
            else if (variable != null)
            {
                return(variable.Convert());
            }
            else if (term != null)
            {
                return(term.Convert());
            }
            else if (acTerm != null)
            {
                return(acTerm.Convert());
            }
            else
            {
                throw new Exception("Unexpected type: " + termIn.GetType().FullName);
            }
        }
コード例 #3
0
 public InterpreterTerm(TrsTermBase root)
 {
     if (root == null)
     {
         throw new ArgumentException("Root may not be null", "root");
     }
     RootTerm = root;
 }
コード例 #4
0
        public List <UnificationResult> GetUnifier(TrsTermBase ruleHead, TrsTermBase matchTerm)
        {
            List <UnificationResult> unifiers = new List <UnificationResult>();

            for (int i = 0; i < 1; i++)
            {
                var tempResult = new UnificationResult();
                tempResult.Unifier = new List <Substitution>();
                foreach (var variable in ruleHead.GetVariables())
                {
                    tempResult.Unifier.Add(new Substitution {
                        SubstitutionTerm = new TrsNumber(i.ToString()), Variable = variable
                    });
                }
                tempResult.Succeed = true;
                unifiers.Add(tempResult);
            }
            return(unifiers);
        }
コード例 #5
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;
 }
コード例 #6
0
ファイル: ArithmaticUnifier.cs プロジェクト: sadeslandes/TRL
        /// <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
            });
        }
コード例 #7
0
ファイル: Interpreter.cs プロジェクト: sadeslandes/TRL
        /// <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);
        }
コード例 #8
0
        public TrsTermBase Evaluate(TrsTermBase termIn)
        {
            var tIn   = termIn as TrsTerm;
            var tInAc = termIn as TrsAcTerm;

            if (tIn != null)
            {
                if (tIn.Arguments.Count != 2)
                {
                    return(termIn);
                }
                if (!(tIn.Arguments[0] is TrsNumber) || !(tIn.Arguments[1] is TrsNumber))
                {
                    return(termIn);
                }
                var    numLhs = Convert.ToDouble(((TrsNumber)tIn.Arguments[0]).Value);
                var    numRhs = Convert.ToDouble(((TrsNumber)tIn.Arguments[1]).Value);
                double retVal;
                switch (tIn.Name.ToLower())
                {
                case Subtraction:
                    retVal = numLhs - numRhs;
                    break;

                case Divide:
                    if (numRhs == 0)
                    {
                        return(tIn);
                    }
                    else
                    {
                        retVal = numLhs / numRhs;
                    }
                    break;

                default:
                    return(tIn);
                }
                return(new TrsNumber(retVal.ToString()));
            }
            else if (tInAc != null)
            {
                if (tInAc.TotalCardinality < 2)
                {
                    throw new InvalidProgramException("AC term with less than 2 arguments");
                }
                if (tInAc.OnfArguments.Where(arg => arg.Term is TrsNumber).Select(arg => arg.Cardinality).Count() != tInAc.TotalCardinality)
                {
                    return(tInAc);
                }
                if (tInAc.Name == Addition)
                {
                    return(new TrsNumber(tInAc.ExpandedArguments.Select(arg => Convert.ToDouble(((TrsNumber)arg).Value)).Sum().ToString()));
                }
                else if (tInAc.Name == Multiply)
                {
                    double retVal = 1.0;
                    foreach (var number in tInAc.ExpandedArguments.Select(arg => Convert.ToDouble(((TrsNumber)arg).Value)))
                    {
                        retVal *= number;
                    }
                    return(new TrsNumber(retVal.ToString()));
                }
                else
                {
                    return(tInAc);
                }
            }
            else
            {
                return(termIn);
            }
        }
コード例 #9
0
 public override TrsTermBase CreateCopyAndReplaceSubTerm(TrsTermBase termToReplace, TrsTermBase replacementTerm)
 {
     return(this);
 }
コード例 #10
0
 public List <UnificationResult> GetUnifier(TrsTermBase termHead, TrsTermBase matchTerm)
 {
     return(GetMgu(new Equation {
         Lhs = termHead, Rhs = matchTerm
     }, matchTerm.GetVariables()));
 }
コード例 #11
0
        /// <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());
        }