Ejemplo n.º 1
0
        private void FindSmallestNodeData(
            HashSet <TNode> keys,
            Dictionary <TNode, DynamicGraphNodeData <TNode, TCost, TEdge> > lookUp,
            out TNode smallestNode,
            out DynamicGraphNodeData <TNode, TCost, TEdge> smallestEdge
            )
        {
            Contract.Requires(keys != null);
            Contract.Requires(keys.Count > 0);
            Contract.Requires(lookUp != null);
            Contract.Requires(lookUp.Count > 0);
            Contract.Requires(lookUp.Count >= keys.Count);
            Contract.Requires(Contract.ForAll(lookUp.Values, x => x != null));
            Contract.Requires(Contract.ForAll(keys, key => key != null && lookUp.ContainsKey(key)));
            Contract.Ensures(Contract.ValueAtReturn(out smallestNode) != null);
            Contract.Ensures(Contract.ValueAtReturn(out smallestEdge) != null);

            using (var enumerator = keys.GetEnumerator()) {
                if (!enumerator.MoveNext())
                {
                    throw new ArgumentException("keys is empty", "keys");
                }
                var currentNode = enumerator.Current;

                //var smallest = new KeyValuePair<TNode, DynamicGraphNodeData<TNode, TCost, TEdge>>(currentNode, lookUp[currentNode]);
                smallestNode = currentNode;
                smallestEdge = lookUp[currentNode];
                Contract.Assume(smallestEdge != null);

                while (enumerator.MoveNext())
                {
                    currentNode = enumerator.Current;

                    var currentData = lookUp[currentNode];
                    Contract.Assume(currentData != null);

                    if (CostComparer.Compare(smallestEdge.Cost, currentData.Cost) > 0)
                    {
                        smallestNode = currentNode;
                        smallestEdge = currentData;
                    }
                }
            }
            if (null == smallestNode)
            {
                throw new ArgumentException("null keys are not allowed", "keys");
            }
            if (null == smallestEdge)
            {
                throw new ArgumentException("null edge contained in edge look-up", "lookUp");
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Finds a graph path from the <paramref name="start"/> node to the <paramref name="target"/> node.
        /// </summary>
        /// <param name="start">The node to begin the path search from.</param>
        /// <param name="target">The target node of the search.</param>
        /// <returns>The shortest path from the start node to the target node if one exists.</returns>
        /// <exception cref="System.ArgumentException">Thrown if a node or edge encountered within the graph is <c>null</c>.</exception>
        public ReadOnlyCollection <DynamicGraphNodeData <TNode, TCost, TEdge> > FindPath(TNode start, TNode target)
        {
            if (null == start)
            {
                throw new ArgumentNullException("start");
            }
            if (null == target)
            {
                throw new ArgumentNullException("target");
            }
            Contract.EndContractBlock();

            // initialize the look-ups
            var nodeDataCache = new Dictionary <TNode, DynamicGraphNodeData <TNode, TCost, TEdge> >(NodeComparer)
            {
                { start, new DynamicGraphNodeData <TNode, TCost, TEdge>(start, default(TCost), default(TEdge)) }
            };
            var visitRequired = new HashSet <TNode>(NodeComparer)
            {
                start
            };                                                              // NOTE: in order for a node to be in this collection it must have a corresponding key in the pathData dictionary.
            DynamicGraphNodeData <TNode, TCost, TEdge> nodeData;
            TNode currentNode;
            var   bestCompleteCost   = default(TCost);
            var   completeRouteFound = false;

            // generate the dynamic path information and find the shortest path
            while (visitRequired.Count != 0)
            {
                DynamicGraphNodeData <TNode, TCost, TEdge> currentNodeData;
                Contract.Assume(nodeDataCache.Count >= visitRequired.Count);
                Contract.Assume(Contract.ForAll(visitRequired, k => k != null && nodeDataCache.ContainsKey(k)));
                FindSmallestNodeData(visitRequired, nodeDataCache, out currentNode, out currentNodeData);
                visitRequired.Remove(currentNode);

                // logic to see if we can short out of checking this node due to it being too long
                if (completeRouteFound)
                {
                    if (CostComparer.Compare(bestCompleteCost, currentNodeData.Cost) <= 0)
                    {
                        continue; // this path is larger than or equal to the best found complete path
                    }
                    if (NodeComparer.Equals(currentNode, target))
                    {
                        bestCompleteCost = currentNodeData.Cost;
                    }
                }
                else if (NodeComparer.Equals(currentNode, target))
                {
                    bestCompleteCost   = currentNodeData.Cost;
                    completeRouteFound = true;
                }

                foreach (var neighborInfo in GetNeighborInfo(currentNode, currentNodeData.Cost))
                {
                    if (ReferenceEquals(null, neighborInfo) || ReferenceEquals(null, neighborInfo.Node))
                    {
                        continue;
                    }

                    if (nodeDataCache.TryGetValue(neighborInfo.Node, out nodeData))
                    {
                        Contract.Assume(nodeData != null);
                        if (CostComparer.Compare(neighborInfo.Cost, nodeData.Cost) < 0)
                        {
                            nodeData.Node = currentNode;
                            nodeData.Cost = neighborInfo.Cost;
                            nodeData.Edge = neighborInfo.Edge;
                            visitRequired.Add(neighborInfo.Node);
                        }
                    }
                    else
                    {
                        nodeDataCache.Add(
                            neighborInfo.Node,
                            new DynamicGraphNodeData <TNode, TCost, TEdge>(currentNode, neighborInfo.Cost, neighborInfo.Edge));
                        visitRequired.Add(neighborInfo.Node);
                    }
                }
            }

            // build the final result path
            if (nodeDataCache.TryGetValue(target, out nodeData))
            {
                Contract.Assume(nodeData != null);
                var pathResult = new List <DynamicGraphNodeData <TNode, TCost, TEdge> > {
                    new DynamicGraphNodeData <TNode, TCost, TEdge>(target, nodeData.Cost, nodeData.Edge)
                };
                currentNode = nodeData.Node;
                if (null == currentNode)
                {
                    return(null);
                }
                while (nodeDataCache.TryGetValue(currentNode, out nodeData))
                {
                    Contract.Assume(nodeData != null);
                    pathResult.Add(new DynamicGraphNodeData <TNode, TCost, TEdge>(currentNode, nodeData.Cost, nodeData.Edge));
                    if (Equals(currentNode, start))
                    {
                        break;
                    }
                    currentNode = nodeData.Node;
                    if (null == currentNode)
                    {
                        return(null);
                    }
                }
                pathResult.Reverse();
                return(new ReadOnlyCollection <DynamicGraphNodeData <TNode, TCost, TEdge> >(pathResult));
            }

            return(null); // no path was found
        }