public void Add_Variable_Tag_SimpleWFN(string n1, string tag, string expectedResult, Refactorization r)
        {
            string result = string.Empty;
            if(r == Refactorization.New)
            {
                SimpleName name = new SimpleName(n1);
                SimpleName resName = null;
                for (long i = 0; i < reps; i++)
                {
                    resName = SimpleWFN.AddVariableTag(name, tag);
                }
                result = resName.ToString();
            }
            else if(r == Refactorization.Current)
            {
                Name name = Name.BuildName(n1);
                Name resName = null;
                for (long i = 0; i < reps; i++)
                {
                    resName = name.ReplaceUnboundVariables("_tag");
                }
                result = RemoveWhiteSpace(resName.ToString());
            }

            Assert.AreEqual(expectedResult, result);
        }
        public void Unify_NonUnifiableNames_False(string n1, string n2, Refactorization r)
        {
            IEnumerable<Substitution> bindings = new List<Substitution>();
            var isUnifiable = true;

            if (r == Refactorization.Current)
            {
                var name1 = Name.BuildName(n1);
                var name2 = Name.BuildName(n2);
                for (int i = 0; i < unifierReps; i++)
                {
                    isUnifiable = Unifier.Unify(name1, name2, out bindings);
                }
            }else if(r == Refactorization.New)
            {
                var name1 = new SimpleName(n1);
                var name2 = new SimpleName(n2);
                for (int i = 0; i < unifierReps; i++)
                {
                    isUnifiable = SimpleUnifier.Unify(name1, name2, out bindings);
                }
            }
            Assert.That(!isUnifiable);
            Assert.That(bindings == null);
        }
示例#3
0
        //return the idx jump on the valName or -1 if it can't add the substitution
        private static int FindSubsAux(Literal var, Literal val, SimpleName valName, IDictionary <string, Substitution> bindings)
        {
            //first, analyse if the value is a composed name or a single parameter
            string valDescription;
            int    valLiteralCount;

            if (val.type == LiteralType.Root)
            {
                SimpleName auxName = null;
                auxName         = SimpleWFN.BuildNameFromContainedLiteral(valName, val);
                valDescription  = auxName.ToString();
                valLiteralCount = auxName.literals.Count;
            }
            else
            {
                valDescription  = val.description;
                valLiteralCount = 1;
            }

            //check if a binding for the same variable already exists
            Substitution existingSub = null;

            bindings.TryGetValue(var.description, out existingSub);
            if (existingSub != null)
            {
                if (existingSub.SubValue.ToString().RemoveWhiteSpace().EqualsIgnoreCase(valDescription))
                {
                    return(valLiteralCount);
                }
                else
                {
                    return(-1);
                }
            }
            //if there was no existing binding to the variable
            try
            {
                bindings[var.description] = new Substitution(var.description, valDescription);
                return(valLiteralCount);
            }
            catch (BadSubstitutionException)
            {
                return(-1);
            }
        }
示例#4
0
        public static SimpleName MakeGround(SimpleName n, Dictionary <string, SimpleName> bindings)
        {
            var literals = new List <Literal>();

            foreach (var l in n.literals)
            {
                if (bindings.ContainsKey(l.description))
                {
                    var nameValue = bindings[l.description];
                    var subName   = new SimpleName(nameValue.literals);
                    foreach (var subL in subName.literals)
                    {
                        subL.depth += l.depth;
                    }
                    literals.AddRange(subName.literals);
                }
                else
                {
                    literals.Add(l);
                }
            }
            return(new SimpleName(literals));
        }
示例#5
0
        /// <summary>
        /// Unifying Method, receives two WellFormedNames and tries
        /// to find a list of Substitutions that will make
        /// both names syntatically equal. The algorithm performs Occur Check,
        /// as such the unification of [X] and Luke([X]) will allways fail.
        ///
        /// The method goes on each symbol (for both names) at a time, and tries to find
        /// a substitution between them. Take into account that the Unification between
        /// [X](John,Paul) and Friend(John,[X]) fails because the algorithm considers [X]
        /// to be the same variable
        /// </summary>
        /// <see cref="FAtiMA.Core.WellFormedNames.Substitution"/>
        /// <see cref="FAtiMA.Core.WellFormedNames.Name"/>
        /// <param name="name1">The first Name</param>
        /// <param name="name2">The second Name</param>
        /// <param name="bindings">The out paramenter for the founded substitutions</param>
        /// <returns>True if the names are unifiable, in this case the bindings list will contain the found Substitutions, otherwise it will be empty</returns>
        public static bool Unify(SimpleName name1, SimpleName name2, out IEnumerable <Substitution> bindings)
        {
            bindings = null;
            if (name1 == null || name2 == null)
            {
                return(false);
            }

            if (SimpleWFN.IsGrounded(name1) && SimpleWFN.IsGrounded(name2))
            {
                if (SimpleWFN.Match(name1, name2))
                {
                    bindings = Enumerable.Empty <Substitution>();
                    return(true);
                }
                else
                {
                    return(false);
                }
            }

            bindings = FindSubst(name1, name2);
            return(bindings != null);
        }
        //return the idx jump on the valName or -1 if it can't add the substitution
        private static int FindSubsAux(Literal var, Literal val, SimpleName valName, IDictionary<string, Substitution> bindings)
        {
            string valDescription;
            SimpleName auxName = null;
            if (val.type == LiteralType.Root)
            {
                auxName = SimpleWFN.BuildNameFromContainedLiteral(valName, val);
                valDescription = auxName.ToString();
            }
            else
            {
                valDescription = val.description;
            }

            //check if a binding for the same variable already exists
            Substitution existingSub = null;
            bindings.TryGetValue(var.description, out existingSub);
            if (existingSub != null)
            {
                if (existingSub.Value.ToString().RemoveWhiteSpace().EqualsIgnoreCase("valDescription"))
                    return 1;
                else return -1;
            }
            //if there was no existing binding to the variable
            try
            {
                bindings[var.description] = new Substitution(var.description, valDescription);
                if (var.type == LiteralType.Param && val.type == LiteralType.Root)
                    return auxName.literals.Count;
                else return 1;
            }
            catch (BadSubstitutionException)
            {
                return -1;
            }
        }
        private static IEnumerable<Substitution> FindSubst(SimpleName n1, SimpleName n2)
        {
            // SubstitutionSet bindings = new SubstitutionSet();
            Dictionary<string, Substitution> bindings = new Dictionary<string, Substitution>();
            var arrayLit1 = n1.literals.ToArray();
            var arrayLit2 = n2.literals.ToArray();
            var idx1 = 0;
            var idx2 = 0;

            do
            {
                var l1 = arrayLit1[idx1];
                var l2 = arrayLit2[idx2];
                //neither literal is a variable
                if (!SimpleWFN.IsVariable(l1) && !SimpleWFN.IsVariable(l2))
                {
                    if (l1.description.EqualsIgnoreCase(l2.description))
                    {
                        idx1++; idx2++;
                        continue;
                    }
                    else { return null; }
                }
                //both literals are a variable
                if (SimpleWFN.IsVariable(l1) && SimpleWFN.IsVariable(l2))
                {
                    if (!l1.description.EqualsIgnoreCase(l2.description))
                    {
                        if (bindings.ContainsKey(l1.description))
                            return null;
                        bindings[l1.description] = new Substitution(l1.description, l2.description);
                    }
                    idx1++; idx2++;
                    continue;
                }
                //only l1 is a variable
                if (SimpleWFN.IsVariable(l1) && !SimpleWFN.IsVariable(l2))
                {
                    var res = FindSubsAux(l1, l2, n2, bindings);
                    if (res == -1) return null;
                    else { idx1++; idx2 += res; continue; }
                }
                //only l2 is a variable
                if (!SimpleWFN.IsVariable(l1) && SimpleWFN.IsVariable(l2))
                {
                    var res = FindSubsAux(l2, l1, n1, bindings);
                    if (res == -1) return null;
                    else { idx1 += res; idx2++; continue; }
                }
                throw new Exception("Unexpected Situation");
            } while (idx1 < arrayLit1.Length && idx2 < arrayLit2.Length);

            if (idx1 == arrayLit1.Length && idx2 == arrayLit2.Length)
            {
                return bindings.Values; // full match
            }
            else
            {
                return null; // only partial match
            };
        }
        //not really needed for now but might be useful for building sub names
        public static SimpleName BuildNameFromNLiteral(SimpleName name, int n)
        {
            if (name.literals[n].type != LiteralType.Root)
                return new SimpleName(name.literals[n].description);

            var list = name.literals.Skip(n + 1).TakeWhile(l => l.depth > name.literals[n].depth);
            return new SimpleName(list.Prepend(name.literals[n]));
        }
示例#9
0
        private static IEnumerable <Substitution> FindSubst(SimpleName n1, SimpleName n2)
        {
            // SubstitutionSet bindings = new SubstitutionSet();
            Dictionary <string, Substitution> bindings = new Dictionary <string, Substitution>();
            var idx1 = 0;
            var idx2 = 0;

            do
            {
                var l1 = n1.literals[idx1];
                var l2 = n2.literals[idx2];
                //neither literal is a variable
                if (!SimpleWFN.IsVariable(l1) && !SimpleWFN.IsVariable(l2))
                {
                    if (l1.description.EqualsIgnoreCase(l2.description))
                    {
                        idx1++; idx2++;
                        continue;
                    }
                    else
                    {
                        return(null);
                    }
                }
                //both literals are a variable
                if (SimpleWFN.IsVariable(l1) && SimpleWFN.IsVariable(l2))
                {
                    if (!l1.description.EqualsIgnoreCase(l2.description))
                    {
                        if (bindings.ContainsKey(l1.description))
                        {
                            return(null);
                        }
                        bindings[l1.description] = new Substitution(l1.description, l2.description);
                    }
                    idx1++; idx2++;
                    continue;
                }
                //only l1 is a variable
                if (SimpleWFN.IsVariable(l1) && !SimpleWFN.IsVariable(l2))
                {
                    var res = FindSubsAux(l1, l2, n2, bindings);
                    if (res == -1)
                    {
                        return(null);
                    }
                    else
                    {
                        idx1++; idx2 += res; continue;
                    }
                }
                //only l2 is a variable
                if (!SimpleWFN.IsVariable(l1) && SimpleWFN.IsVariable(l2))
                {
                    var res = FindSubsAux(l2, l1, n1, bindings);
                    if (res == -1)
                    {
                        return(null);
                    }
                    else
                    {
                        idx1 += res; idx2++; continue;
                    }
                }
                throw new Exception("Unexpected Situation");
            } while (idx1 < n1.literals.Count && idx2 < n2.literals.Count);

            if (idx1 == n1.literals.Count && idx2 == n2.literals.Count)
            {
                return(bindings.Values); // full match
            }
            else
            {
                return(null); // only partial match
            };
        }
示例#10
0
 public static bool HasSelf(SimpleName name)
 {
     return(name.literals.Any(l => l.description == Name.SELF_STRING));
 }
示例#11
0
 public static IEnumerable <Literal> GetVariables(SimpleName name)
 {
     return(name.literals.Where(l => IsVariable(l)));
 }
示例#12
0
 public static bool HasSelf(SimpleName name)
 {
     return name.literals.Any(l => l.description == Name.SELF_STRING);
 }
示例#13
0
 public static IEnumerable<Literal> GetVariables(SimpleName name)
 {
     return name.literals.Where(l => IsVariable(l));
 }
示例#14
0
 public static int GetNumberOfTerms(SimpleName name)
 {
     return name.literals.Count(l => l.depth <= 1);
 }
示例#15
0
        //not really needed for now but might be useful for building sub names
        public static List<SimpleName> GetAllComposedNames(SimpleName name)
        {
            List<SimpleName> res = new List<SimpleName>();

            for (int i = 1; i < name.literals.Count; i++)
            {
                if (name.literals.ElementAt(i).type == LiteralType.Root)
                {
                    res.Add(BuildNameFromNLiteral(name, i));
                }
            }
            return res;
        }
示例#16
0
 /// <summary>
 /// Verifies if a specific variable is contained inside this Name.
 /// </summary>
 /// <param name="variable">The variable Name we want to verify</param>
 /// <exception cref="ArgumentException">Thrown if the given argument is not a variable definition.</exception>
 public static bool ContainsVariable(SimpleName name, string variable)
 {
     var v = Name.BuildName(variable);
     if (!v.IsVariable)
         throw new ArgumentException("Invalid variable", variable);
     return GetVariables(name).Any(l => l.description.EqualsIgnoreCase(variable));
 }
示例#17
0
 public static bool ContainsUniversal(SimpleName name)
 {
     return name.literals.Any(l => l.description == Name.UNIVERSAL_STRING);
 }
示例#18
0
 public static int GetNumberOfTerms(SimpleName name)
 {
     return(name.literals.Count(l => l.depth <= 1));
 }
示例#19
0
 public static bool ContainsUniversal(SimpleName name)
 {
     return(name.literals.Any(l => l.description == Name.UNIVERSAL_STRING));
 }
示例#20
0
 public static bool IsGrounded(SimpleName name)
 {
     return name.isGrounded;
 }
示例#21
0
 public static bool IsGrounded(SimpleName name)
 {
     return(name.isGrounded);
 }
示例#22
0
        public static SimpleName MakeGround(SimpleName n, Dictionary<string, SimpleName> bindings)
        {
            var literals = new List<Literal>();

            foreach (var l in n.literals)
            {
                if (bindings.ContainsKey(l.description))
                {
                    var nameValue = bindings[l.description];
                    var subName = new SimpleName(nameValue.literals);
                    foreach(var subL in subName.literals)
                    {
                        subL.depth += l.depth;
                    }
                    literals.AddRange(subName.literals);
                }
                else
                {
                    literals.Add(l);
                }
            }
            return new SimpleName(literals);
        }
示例#23
0
        public static bool Match(SimpleName n1, SimpleName n2)
        {
            if (SimpleWFN.GetNumberOfTerms(n1) != SimpleWFN.GetNumberOfTerms(n2))
            {
                return(false);
            }

            var idx1 = 0;
            var idx2 = 0;

            do
            {
                var l1 = n1.literals[idx1];
                var l2 = n2.literals[idx2];

                //auxiliary variables
                bool typesMatch      = l1.type == l2.type;
                bool l1IsUniv        = l1.description == Name.UNIVERSAL_STRING;
                bool l2IsUniv        = l2.description == Name.UNIVERSAL_STRING;
                bool existsUniversal = l1IsUniv || l2IsUniv;

                //The easy matching scenario is when both types match
                if (typesMatch)
                {
                    if (existsUniversal || l1.description.EqualsIgnoreCase(l2.description))
                    {
                        idx1++; idx2++;
                        continue;
                    }
                    return(false); //no universals and different descritions
                }

                //eg. matching S with S(A)
                if (!typesMatch && !existsUniversal)
                {
                    return(false);
                }

                //l1 is a universal and l2 has a different type
                if (!typesMatch && l1IsUniv)
                {
                    //l1 is a universal parameter and n2 is a root
                    if (l1.type == LiteralType.Param)
                    {
                        // the index on n2 must jump until it reaches the depth of l1 again
                        idx2 += FindJumpUntilDepthN(n2.literals, idx2, l1.depth);
                        idx1++;
                        continue;
                    }
                    //a root universal never matches any parameter except a universal
                    if (l1.type == LiteralType.Root && !l2IsUniv)
                    {
                        return(false);
                    }
                }

                //the last case is when l2 is the universal
                if (!typesMatch && l2IsUniv)
                {
                    if (l2.type == LiteralType.Param)
                    {
                        // the index on n2 must jump until it reaches the depth of n1 again
                        idx1 += FindJumpUntilDepthN(n1.literals, idx1, l2.depth);
                        idx2++;
                        continue;
                    }
                    //a root universal never matches any parameter except a universal
                    if (l2.type == LiteralType.Root && !l1IsUniv)
                    {
                        return(false);
                    }
                }
            } while (idx1 < n1.literals.Count && idx2 < n2.literals.Count);

            if (idx1 == n1.literals.Count && idx2 == n2.literals.Count)
            {
                return(true); // full match
            }
            else
            {
                return(false); // only partial match
            }
        }
示例#24
0
        public static bool Match(SimpleName n1, SimpleName n2)
        {
            if (SimpleWFN.GetNumberOfTerms(n1) != SimpleWFN.GetNumberOfTerms(n2))
                return false;

            var idx1 = 0;
            var idx2 = 0;
            do
            {
                var l1 = n1.literals[idx1];
                var l2 = n2.literals[idx2];

                //auxiliary variables
                bool typesMatch = l1.type == l2.type;
                bool l1IsUniv = l1.description == Name.UNIVERSAL_STRING;
                bool l2IsUniv = l2.description == Name.UNIVERSAL_STRING;
                bool existsUniversal = l1IsUniv || l2IsUniv;

                //The easy matching scenario is when both types match
                if (typesMatch)
                {
                    if (existsUniversal || l1.description.EqualsIgnoreCase(l2.description))
                    {
                        idx1++; idx2++;
                        continue;
                    }
                    return false; //no universals and different descritions
                }

                //eg. matching S with S(A)
                if (!typesMatch && !existsUniversal)
                {
                    return false;
                }

                //l1 is a universal and l2 has a different type
                if (!typesMatch && l1IsUniv)
                {
                    //l1 is a universal parameter and n2 is a root
                    if (l1.type == LiteralType.Param)
                    {
                        // the index on n2 must jump until it reaches the depth of l1 again
                        idx2 += FindJumpUntilDepthN(n2.literals, idx2, l1.depth);
                        idx1++;
                        continue;
                    }
                    //a root universal never matches any parameter except a universal
                    if (l1.type == LiteralType.Root && !l2IsUniv)
                        return false;
                }

                //the last case is when l2 is the universal
                if (!typesMatch && l2IsUniv)
                {
                    if (l2.type == LiteralType.Param)
                    {
                        // the index on n2 must jump until it reaches the depth of n1 again
                        idx1 += FindJumpUntilDepthN(n1.literals, idx1, l2.depth);
                        idx2++;
                        continue;
                    }
                    //a root universal never matches any parameter except a universal
                    if (l2.type == LiteralType.Root && !l1IsUniv)
                        return false;
                }
            } while (idx1 < n1.literals.Count && idx2 < n2.literals.Count);

            if (idx1 == n1.literals.Count && idx2 == n2.literals.Count)
            {
                return true; // full match
            }
            else
            {
                return false; // only partial match
            }
        }
示例#25
0
 public void HasSelf(string nStr, bool expectedResult, Refactorization r)
 {
     bool result = false;
     if (r == Refactorization.Current)
     {
         var name = Name.BuildName(nStr);
         for (long i = 0; i < reps; i++)
         {
             result = name.HasSelf();
         }
     }
     else if (r == Refactorization.New)
     {
         var name = new SimpleName(nStr);
         for (long i = 0; i < reps; i++)
         {
             result = SimpleWFN.HasSelf(name);
         }
     }
     Assert.AreEqual(expectedResult, result);
 }
示例#26
0
        public void MatchNames_True(string n1, string n2, Refactorization r)
        {
            bool result = false;

            if(r == Refactorization.Current)
            {
                var name = Name.BuildName(n1);
                var name2 = Name.BuildName(n2);
                for (long i = 0; i < reps; i++)
                {
                    result = name.Match(name2);
                }
            }
            else if (r == Refactorization.New)
            {
                var name = new SimpleName(n1);
                var name2 = new SimpleName(n2);
                for (long i = 0; i < reps; i++)
                {
                    result = SimpleWFN.Match(name, name2);
                }
            }
            Assert.IsTrue(result);
        }
示例#27
0
 public static SimpleName RemoveVariableTag(SimpleName name, string tag)
 {
     var clone = new SimpleName(name.literals);
     foreach (var v in GetVariables(clone))
     {
         v.description = v.description.Replace(tag + "]", "]");
     }
     return clone;
 }
示例#28
0
        public static SimpleName BuildNameFromContainedLiteral(SimpleName name, Literal literal)
        {
            if (literal.type != LiteralType.Root)
                return new SimpleName(new Literal[] { literal });

            var i = name.literals.IndexOf(literal);
            var list = name.literals.Skip(i+1).TakeWhile(l => l.depth > literal.depth);
            return new SimpleName(list.Prepend(literal));
        }
示例#29
0
        public void MakeGround_GroundedName(string n1, string var, string sub, string expectedResult, Refactorization r)
        {
            String result = string.Empty;

            if (r == Refactorization.New)
            {
                var name = new SimpleName(n1);
                SimpleName nameResult = null;
                Dictionary<string, SimpleName> subs = new Dictionary<string, SimpleName>();
                subs[var] = new SimpleName(sub);
                for (long i = 0; i < reps; i++)
                {
                    nameResult = SimpleWFN.MakeGround(name, subs);
                }
                result = nameResult.ToString();
            }
            else if (r == Refactorization.Current)
            {
                var name = Name.BuildName(n1);
                Name nameResult = null;
                SubstitutionSet subSet = new SubstitutionSet();
                subSet.AddSubstitution(new Substitution("[x]/J(I)"));
                for (long i = 0; i < reps; i++)
                {
                    nameResult = name.MakeGround(subSet);
                }
            }
            Assert.AreEqual(expectedResult, result);
        }
示例#30
0
 public static SimpleName ReplaceLiterals(SimpleName name, string oldLit, string newLit)
 {
     var clone = new SimpleName(name.literals);
     foreach (var l in clone.literals.Where(l => l.description == oldLit))
     {
         l.description = newLit;
     }
     return clone;
 }
示例#31
0
        public void ReplaceLiterals(string n1, string t1, string t2, string expectedResult, Refactorization r)
        {
            string resultStr = string.Empty;

            if(r == Refactorization.Current)
            {
                Name result = null;
                var name = Name.BuildName(n1);
                for (long i = 0; i < reps; i++)
                {
                    result = name.SwapTerms((Name)t1, (Name)t2);
                }
                resultStr = RemoveWhiteSpace(result.ToString());
            }else if(r == Refactorization.New)
            {
                SimpleName result = null;
                var name = new SimpleName(n1);
                for (long i = 0; i < reps; i++)
                {
                    result = SimpleWFN.ReplaceLiterals(name, t1, t2);
                }
                resultStr = result.ToString();
            }

            Assert.That(string.Equals(resultStr, expectedResult, StringComparison.InvariantCultureIgnoreCase));
        }
        public void Unify_UnifiableNames_True(string n1, string n2, string[] result, Refactorization r)
        {
            var expectedBindings = result.Select(s => new Substitution(s));
            IEnumerable<Substitution> bindings = null;
            var isUnifiable = false;

            if(r == Refactorization.Current)
            {
                var name1 = Name.BuildName(n1);
                var name2 = Name.BuildName(n2);
                for (int i = 0; i < unifierReps; i++)
                {
                    isUnifiable = Unifier.Unify(name1, name2, out bindings);
                }
            }
            else if(r == Refactorization.New)
            {
                var name1 = new SimpleName(n1);
                var name2 = new SimpleName(n2);

                for (int i = 0; i < unifierReps; i++)
                {
                    isUnifiable = SimpleUnifier.Unify(name1, name2, out bindings);
                }
            }
            Assert.That(isUnifiable);
            if (result.Any())
            {
                Assert.That(bindings, Is.EquivalentTo(expectedBindings));
            }
            else
            {
                Assert.That(bindings.Count() == 0);
            }
        }
示例#33
0
 public void ToString(string n1, string expectedResult, Refactorization r)
 {
     string result = string.Empty;
     if (r == Refactorization.Current)
     {
         var name = Name.BuildName(n1);
         for (long i = 0; i < reps; i++)
         {
             result = name.ToString();
         }
         result = RemoveWhiteSpace(result);
     }
     else if (r == Refactorization.New)
     {
         var name = new SimpleName(n1);
         for (long i = 0; i < reps; i++)
         {
             result = name.ToString();
         }
     }
     Assert.That(string.Equals(expectedResult, result, StringComparison.InvariantCultureIgnoreCase));
 }
示例#34
0
        /// <summary>
        /// Unifying Method, receives two WellFormedNames and tries 
        /// to find a list of Substitutions that will make 
        /// both names syntatically equal. The algorithm performs Occur Check,
        /// as such the unification of [X] and Luke([X]) will allways fail.
        /// 
        /// The method goes on each symbol (for both names) at a time, and tries to find 
        /// a substitution between them. Take into account that the Unification between
        /// [X](John,Paul) and Friend(John,[X]) fails because the algorithm considers [X]
        /// to be the same variable
        /// </summary>
        /// <see cref="FAtiMA.Core.WellFormedNames.Substitution"/>
        /// <see cref="FAtiMA.Core.WellFormedNames.Name"/>
        /// <param name="name1">The first Name</param>
        /// <param name="name2">The second Name</param>
        /// <param name="bindings">The out paramenter for the founded substitutions</param>
        /// <returns>True if the names are unifiable, in this case the bindings list will contain the found Substitutions, otherwise it will be empty</returns>
        public static bool Unify(SimpleName name1, SimpleName name2, out IEnumerable<Substitution> bindings)
        {
            bindings = null;
            if (name1 == null || name2 == null)
                return false;

            if (SimpleWFN.IsGrounded(name1) && SimpleWFN.IsGrounded(name2))
            {
                if (SimpleWFN.Match(name1, name2))
                {
                    bindings = Enumerable.Empty<Substitution>();
                    return true;
                }
                else   {  return false; }
            }

            bindings = FindSubst(name1, name2);
            return bindings != null;
        }