Exemple #1
0
        /// <summary>
        /// Navigates this node (and recusively into child nodes) for a match to the path passed as an argument
        /// whilst processing the referenced request. This matching algorithm is a highly restricted version of 
        /// depth-first search, also known as backtracking (hence the name).
        /// </summary>
        /// <param name="position">The position in the search path currently being evaluated</param>
        /// <param name="matchState">The type of wildcard match to store in the Wildcards dictionary</param>
        /// <param name="wildcardMatches">The contents of the user input absorbed by the AIML wildcards "_" and "*"</param>
        /// <param name="node">The node we're currently "visiting"</param>
        /// <returns>The template to process to generate the output</returns>
        private bool BackTrack(int position, string matchState, StringBuilder wildcardMatches, Node node)
        {
            // Check for timeout (and check of last resort should there be circular AIML references)
            if (this.TimeoutAfter < DateTime.Now)
            {
                this.hasTimedOut = true;
                throw new LearnException(String.Format(CultureInfo.CurrentCulture, rm.GetString("QueryTimedOut"), String.Join(" ", this.path)));
            }

            // Check if the query has found a leaf node
            if (node.Children.Count == 0)
            {
            	// if there are still words in the path then add them to the wildcard match
            	// (should they be required)
                if (position < this.path.Length)
                {
                    for (int i = position; i < this.path.Length; i++)
                    {
                        wildcardMatches.Append(this.path[i] + " ");
                    }
                }
                if (node.Template != null)
                {
                    this.Node = node;
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if (position == this.path.Length)
            {
                // as there is no more path to process then the result is the current node
                // (whose template *might* be null - but that needs to be dealt with in the 
                // template handling code - this method simply wants to find nodes).
                if (this.Node == null)
                {
                    return false;
                }
                else
                {
                    this.Node = node;
                    return true;
                }
            }
            else
            {
                // check for update to the matchstate
                Match m = Regex.Match(this.path[position], "(<.[^(><.)]+>)");
                if (m.Success)
                {
                    matchState = m.Value.Substring(1, m.Value.Length - 2) + "star";
                }

                // search in the children of the current node
                if(node.Children.ContainsKey("_"))
                {
                    // first option is to see if the node has a child denoted by the "_" wildcard.
                    // "_" comes first in precedence in the AIML alphabet
                    StringBuilder newWildcardMatch = new StringBuilder();
                    newWildcardMatch.Append(this.path[position]+" ");
                    if (this.BackTrack((position + 1),matchState, newWildcardMatch, node.Children["_"]))
                    {
                        this.StoreWildcard(matchState, newWildcardMatch.ToString().Trim());
                        return true;
                    }
                }
                string key = this.path[position].ToUpper(CultureInfo.InvariantCulture);
                if (node.Children.ContainsKey(key))
                {
                    // second option - the node may have contained a "_" child, but led to no match
                    // or it didn't contain a "_" child at all. So check for a matching node corresponding 
                    // to the word found in the current position in the path.
                    StringBuilder newWildcardMatch = new StringBuilder();
                    if (this.BackTrack((position + 1), matchState, newWildcardMatch, node.Children[key]))
                    {
                        if (newWildcardMatch.Length > 0)
                        {
                            this.StoreWildcard(matchState, newWildcardMatch.ToString().Trim());
                        }
                        return true;
                    }
                }
                if (node.Children.ContainsKey("*"))
                {
                    // third option - check to see if the node has a child representing the "*" wildcard. 
                    // "*" comes last in precedence in the AIML alphabet.
                    StringBuilder newWildcardMatch = new StringBuilder();
                    newWildcardMatch.Append(this.path[position] + " ");
                    if (this.BackTrack((position + 1), matchState, newWildcardMatch, node.Children["*"]))
                    {
                        this.StoreWildcard(matchState, newWildcardMatch.ToString().Trim());
                        return true;
                    }
                }
                if ((node.Word == "_") || (node.Word == "*"))
                {
                    // so far the query has failed to find a match at all: the node's children contain neither 
                    // a "_", the word at this.Path[position], or "*" as a means of denoting a child node. However, 
                    // if this node itself represents a wildcard then the search continues to be
                    // valid if we proceed with the tail.
                    wildcardMatches.Append(this.path[position] + " ");
                    return this.BackTrack((position + 1), matchState, wildcardMatches, node);
                }
                // If we get here then we're at a dead end so return false. Hopefully, if the
                // AIML files have been set up to include a "* <that> * <topic> *" catch-all this
                // state won't be reached. Remember to empty the surplus to requirements wildcard matches
                // so the query doesn't pollute the wildcard matches back up the search tree.
                if (wildcardMatches.Length > 0)
                {
                    wildcardMatches.Remove(0, wildcardMatches.Length);
                }
                return false;
            }
        }
Exemple #2
0
        /// <summary>
        /// Adds extra branches and templates to the graphmaster
        /// </summary>
        /// <param name="path">the path from the current parent that identifies the template to learn</param>
        /// <param name="position">the position in the path currently being evaluated</param>
        /// <param name="template">the template to find at the end of the path</param>
        /// <param name="source">the URI that was the source of the category that points to the template</param>
        private Node AddNode(string[] path, int position, string template, string source)
        {
            // check we're not at the leaf node
            if (position == path.Length)
            {
                this.Template = template;
                this.Source = source;
                return this;
            }
            else
            {
                // requires further child nodes for this category to be fully mapped into the graphmaster
                string firstWord = path[position].ToUpper(CultureInfo.InvariantCulture);
                position++;

                // pass the handling of this sentence down the branch to a child node
                if (this.Children.ContainsKey(firstWord))
                {
                    Node childNode = this.Children[firstWord];
                    return childNode.AddNode(path, position, template, source);
                }
                else
                {
                    // new child node needed
                    Node childNode = new Node(firstWord);
                    this.Children.Add(firstWord, childNode);
                    return childNode.AddNode(path, position, template, source);
                }
            }
        }
Exemple #3
0
 /// <summary>
 /// Starts the query from the passed node for the query path with the started on point designated (should this
 /// query be the result of a previous query - we need to have the stopwatch start from the beginning of the 
 /// original query)
 /// </summary>
 /// <param name="node">The node from which the query is to start</param>
 /// <param name="StartedOn">When the query is started from</param>
 public bool Evaluate(Node node, DateTime startedOn)
 {
     this.startedOn = startedOn;
     return this.BackTrack(0, "star", new StringBuilder(), node);
 }