public void TestDijkstra()
        {
            // TODO: Maybe make the graphs class members.
            /// 0 -- 1 -- 2 -- 3
            ///  \        |   /
            ///    \      | /
            ///      4 -- 5
            bool[,] graph1 = {
                                 { false, true,  false, false, true,  false },
                                 { true,  false, true,  false, false, false },
                                 { false, true,  false, true,  false, true  },
                                 { false, false, true,  false, false, true  },
                                 { true,  false, false, false, false, true  },
                                 { false, false, true,  true,  true,  false },
                             };

            SearchGraph searchGraph1 = SearchGraphFromData(graph1);

            Dictionary<int, GraphNode> graphNodes = GetGraphNodesIdIndex(searchGraph1);

            DistanceLookup distanceLookup = new DistanceLookup();
            Assert.IsTrue(distanceLookup.GetDistance(graphNodes[0], graphNodes[0]) == 0, "Failed 0 distance test");
            Assert.IsTrue(distanceLookup.GetDistance(graphNodes[0], graphNodes[5]) == 2, "Wrong distance");
            Assert.IsTrue(distanceLookup.GetDistance(graphNodes[0], graphNodes[3]) == 3, "Wrong distance");
        }
Beispiel #2
0
        /// <summary>
        ///  Finds the nodes in the search graph that can be potential steiner
        ///  nodes. Those form the search space base.
        /// </summary>
        private void buildSearchSpaceBase()
        {
            searchSpaceBase = new List <GraphNode>();

            MinimalSpanningTree leastSolution = new MinimalSpanningTree(targetNodes, distances);

            leastSolution.Span(startFrom: startNodes);

            int maxEdgeDistance = 0;

            foreach (GraphEdge edge in leastSolution.SpanningEdges)
            {
                int edgeDistance = distances.GetDistance(edge);
                if (edgeDistance > maxEdgeDistance)
                {
                    maxEdgeDistance = edgeDistance;
                }
            }

            /*
             * int maxTargetDistance = 0;
             * foreach (GraphNode targetNode in targetNodes)
             * {
             *  int targetDistance = distances.GetDistance(targetNode, startNodes);
             *  if (targetDistance > maxTargetDistance)
             *      maxTargetDistance = targetDistance;
             * }*/

            // Find potential steiner points that are in reasonable vicinity.
            /// TODO: This can surely be improved in some shape or form, but I
            /// can't figure it out right now. Since the GA also has to work well
            /// with larger input sizes, I won't investigate this right now.
            foreach (GraphNode node in searchGraph.nodeDict.Values)
            {
                // This can be a steiner node only if it has more than 2 neighbors.
                if (node.Adjacent.Count > 2)
                {
                    /*
                     * While this would mathematically be correct, it's not a
                     * good criterium for the skill tree. I don't think the
                     * relevant cases can appear and this permits way too many
                     * nodes to be considered that will never be included in an
                     * actual solution.
                     *
                     * /// If every target node is closer to the start than to a certain
                     * /// steiner node, that node can't be needed for the steiner tree.
                     * bool add = false;
                     * foreach (GraphNode targetNode in targetNodes)
                     *  if (distances.GetDistance(targetNode, node) < distances.GetDistance(targetNode, startNodes))
                     *      add = true;
                     * if (add)
                     *  searchSpaceBase.Add(node);
                     */

                    /*
                     * /// This is a pretty handwavy approach... If anybody figures
                     * /// out a case that causes this to fail, let me know please!
                     * if (distances.GetDistance(node, startNodes) < 1.2 * maxTargetDistance)
                     *  searchSpaceBase.Add(node);
                     */

                    // This should be a reasonable approach.
                    bool add = false;
                    foreach (GraphNode targetNode in targetNodes)
                    {
                        if (distances.GetDistance(targetNode, node) < maxEdgeDistance)
                        {
                            add = true;
                        }
                    }
                    if (add)
                    {
                        searchSpaceBase.Add(node);
                    }
                }
            }

            /* ONLY FOR WHEN NODES HAVE INDIVIDUAL WEIGHTS
             * foreach (ushort nodeId in targetSkillnodes)
             * {
             *  searchSpaceBase.Add(SkillTree.Skillnodes[nodeId]);
             * }*/
        }
Beispiel #3
0
        /// <summary>
        ///  Uses Prim's algorithm to build an MST spanning the mstNodes.
        /// </summary>
        /// <param name="startFrom">A GraphNode to start from.</param>
        /// <returns>A list of GraphEdges forming the MST.</returns>
        public List <GraphEdge> Span(GraphNode startFrom)
        {
            /// With n nodes, we can have up to n (actually n-1) edges adjacent to each node.
            HeapPriorityQueue <GraphEdge> adjacentEdgeQueue = new HeapPriorityQueue <GraphEdge>(mstNodes.Count * mstNodes.Count);
            /// Removing all edges that satisfy a property (here a certain "outside"
            /// node) from the queue is not actually trivial, since you could only
            /// iterate over all entries (and you want to avoid that) if you don't
            /// have the references to the edges at hand.
            /// I guess this is the easiest way to do it...
            Dictionary <GraphNode, List <GraphEdge> > edgesLeadingToNode =
                new Dictionary <GraphNode, List <GraphEdge> >();

            foreach (GraphNode node in mstNodes)
            {
                edgesLeadingToNode[node] = new List <GraphEdge>();
            }

            // All nodes that are already included.
            HashSet <GraphNode> inMst = new HashSet <GraphNode>();
            // All nodes that are not yet included.
            HashSet <GraphNode> toAdd = new HashSet <GraphNode>(mstNodes);

            List <GraphEdge> mstEdges = new List <GraphEdge>();

            // Initialize the MST with the start nodes.
            inMst.Add(startFrom);
            toAdd.Remove(startFrom);
            edgesLeadingToNode[startFrom] = new List <GraphEdge>();
            foreach (GraphNode otherNode in toAdd)
            {
                GraphEdge adjacentEdge = new GraphEdge(startFrom, otherNode);
                adjacentEdgeQueue.Enqueue(adjacentEdge, distances.GetDistance(adjacentEdge));
                edgesLeadingToNode[otherNode].Add(adjacentEdge);
            }

            while (toAdd.Count > 0 && adjacentEdgeQueue.Count > 0)
            {
                GraphEdge shortestEdge = adjacentEdgeQueue.Dequeue();
                mstEdges.Add(shortestEdge);
                GraphNode newIn = shortestEdge.outside;


                //if (inMst.Contains(newIn)) throw new Exception();
                //if (!toAdd.Contains(newIn)) throw new Exception("No edge to this node should remain!");

                inMst.Add(newIn);
                toAdd.Remove(newIn);

                // Remove all edges that are entirely inside the MST now.
                foreach (GraphEdge obsoleteEdge in edgesLeadingToNode[newIn])
                {
                    //if (!inMst.Contains(obsoleteEdge.inside)) throw new Exception("This edge's inside node is not inside");
                    adjacentEdgeQueue.Remove(obsoleteEdge);
                }
                edgesLeadingToNode.Remove(newIn);

                // Find all newly adjacent edges and enqueue them.
                foreach (GraphNode otherNode in toAdd)
                {
                    GraphEdge adjacentEdge = new GraphEdge(newIn, otherNode);
                    adjacentEdgeQueue.Enqueue(adjacentEdge, distances.GetDistance(adjacentEdge));
                    edgesLeadingToNode[otherNode].Add(adjacentEdge);
                }
            }
            if (toAdd.Count > 0)
            {
                throw new DistanceLookup.GraphNotConnectedException();
            }

            this.SpanningEdges = mstEdges;
            _isSpanned         = true;
            return(mstEdges);
        }