Ejemplo n.º 1
0
        /// <summary>Gets and returns the successors or predecessors of the given node, omitting paths that correspond to
        /// previously visited states and are not better than the existing path.
        /// </summary>
        /// <param name="parent">The state whose successors or predecessors will be returned.</param>
        /// <param name="statesSeen">A dictionary mapping states to the best known path to that state, or null if
        /// <see cref="GraphSearchBase{S,A}.EliminateDuplicateStates"/> is false.
        /// </param>
        /// <param name="reversed">If true, the predecessors of the node will be retrieved. If false, the successors.</param>
        /// <returns>Returns the new nodes to add to the queue.</returns>
        IEnumerable <Node <StateType, ActionType> > GetNodes(Node <StateType, ActionType> parent,
                                                             Dictionary <StateType, Node <StateType, ActionType> > statesSeen,
                                                             bool reversed)
        {
            IEnumerable <StateActionPair <StateType, ActionType> > statePairs =
                reversed ? BidiProblem.GetPredecessors(parent.State) : Problem.GetSuccessors(parent.State);

            return(statesSeen == null?GetNodes(parent, statePairs)
                       : GetNonDuplicatedNodes(parent, statePairs, statesSeen));
        }
Ejemplo n.º 2
0
        /// <summary>Given the forward and backward chains formed by bidirectional searching, joins them together and returns
        /// a single forward-only solution.
        /// </summary>
        Node <StateType, ActionType> BuildBidirectionalSolution(Node <StateType, ActionType> start,
                                                                Node <StateType, ActionType> end)
        {
            // 'start' contains the solution leading back to the start node, and 'end' contains the solution leading back to
            // the end node. both have the same state. we need to reverse the solution of the end node, and adjust the
            // actions, depths, and costs
            while (end.Parent != null)
            {
                Node <StateType, ActionType> nextEnd = end.Parent;

                end.Action        = BidiProblem.GetSuccessorAction(end.Parent.State, end.State, end.Action);
                end.State         = nextEnd.State;
                end.PathCost      = start.PathCost + (end.Parent == null ? 0 : end.PathCost - end.Parent.PathCost);
                end.Depth         = start.Depth + 1;
                end.Parent        = start;
                end.HeuristicCost = nextEnd.HeuristicCost;

                start = end;
                end   = nextEnd;
            }

            return(start);
        }
Ejemplo n.º 3
0
        /// <summary>This method does all of the work of running a bidirectional search except for ensuring that searching
        /// bidirectionally is safe and starting the limiter, if any.
        /// </summary>
        protected SearchResult FinishBidirectionalSearch(StateType initialState, SearchLimiter limiter,
                                                         out Node <StateType, ActionType> solution)
        {
            solution = new Node <StateType, ActionType>();

            // the queues into which nodes will be placed
            IQueue <Node <StateType, ActionType> > leftFringe, rightFringe;
            // dictionaries keeping track of states that have been visited before, and the best paths to them.
            Dictionary <StateType, Node <StateType, ActionType> > leftStates, rightStates;

            // initialize the search
            leftFringe  = CreateQueue();
            rightFringe = CreateQueue();
            leftStates  = new Dictionary <StateType, Node <StateType, ActionType> >();
            rightStates = EliminateDuplicateStates ? new Dictionary <StateType, Node <StateType, ActionType> >() : null;

            leftFringe.Enqueue(MakeNode(initialState));
            foreach (StateType goalState in BidiProblem.GetGoalStates())
            {
                rightFringe.Enqueue(MakeNode(goalState));
            }

            bool limitHit = false;                                  // keeps track of whether the search has hit some limit preventing it from exploring further

            while (leftFringe.Count != 0 && rightFringe.Count != 0) // while there are still nodes in both open lists
            {
                if (limiter != null && limiter.LimitReached)
                {
                    limitHit = true;
                    break;
                }

                // get a node from the forward search
                Node <StateType, ActionType> leftNode = leftFringe.Dequeue();
                if (Problem.IsGoal(leftNode.State)) // if it's a goal, we've found a forward-only solution, so return it
                {
                    solution = leftNode;
                    return(SearchResult.Success);
                }

                // this proceeds much like standard search...
                if (EliminateDuplicateStates)
                {
                    limitHit |= TryEnqueueNodes(leftFringe, leftNode, leftStates, false);
                }
                else if (leftNode.Depth >= DepthLimit)
                {
                    limitHit = true;
                }
                else
                {
                    foreach (Node <StateType, ActionType> child in GetNodes(leftNode, null, false))
                    {
                        leftFringe.Enqueue(child);

                        Node <StateType, ActionType> existingChild;
                        if (!leftStates.TryGetValue(child.State, out existingChild) || IsNodeBetter(child, existingChild))
                        {
                            leftStates[child.State] = child;
                        }
                    }
                }

                // now take a node from the reverse search
                Node <StateType, ActionType> rightNode = rightFringe.Dequeue();
                // if it has been visited by the forward search, we've found a link between the two
                if (leftStates.TryGetValue(rightNode.State, out leftNode))
                {
                    solution = BuildBidirectionalSolution(leftNode, rightNode); // convert it into a forward-only solution
                    return(SearchResult.Success);                               // and return it
                }

                limitHit |= TryEnqueueNodes(rightFringe, rightNode, rightStates, true);
            }

            // if it gets here, we couldn't find a solution
            return(limitHit ? SearchResult.LimitReached : SearchResult.Failed);
        }