/// <summary>
 /// Writes the edges of the passed graph to the console.
 /// </summary>
 /// <param name="graph">
 /// Graph to print.
 /// </param>
 private static void PrintGraph(IWeightedGraph<IntVertex, FredmanTarjanEdge> graph)
 {
     foreach (var edge in
         graph.Edges.Where(edge => edge.Source < edge.Target))
     {
         Debug.WriteLine("{0} ---> {1}: {2}", edge.Source, edge.Target, edge.Weight);
     }
 }
Пример #2
0
        public static IWeightedGraph <TV, TW> BuildResidualGraph <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                          Func <TW, TW, TW> substractFlowValues,
                                                                          TW zeroValue) where TV : IEquatable <TV> where TW : IComparable
        {
            Dictionary <TV, Vertex <TV> > verteces = new Dictionary <TV, Vertex <TV> >();

            foreach (var vertex in graph.GetAllVerteces())
            {
                verteces.Add(vertex.Value, new Vertex <TV>(vertex.Value));
            }

            GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(true).AddVerteces(verteces.Values);

            foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges())
            {
                IWeightedDirectedEdge <TV, TW> directedEdge = (IWeightedDirectedEdge <TV, TW>)edge;
                TW currentFlow  = directedEdge.GetAttribute <TW>(ATTR_FLOW);
                TW maxFlow      = directedEdge.Weight;
                TW residualFlow = substractFlowValues(maxFlow, currentFlow);

                // Add forward edge with residual flow value as capacity
                if (residualFlow.CompareTo(zeroValue) > 0)
                {
                    Edge <TV, TW> forwardEdge = new Edge <TV, TW>(verteces[directedEdge.OriginVertex.Value],
                                                                  verteces[directedEdge.TargetVertex.Value],
                                                                  residualFlow);
                    forwardEdge.SetAttribute(ATTR_DIRECTION, EdgeDirection.Forward);
                    builder.AddEdge(forwardEdge);
                }

                // Add backward edge with current flow as capacity
                if (currentFlow.CompareTo(zeroValue) > 0)
                {
                    Edge <TV, TW> backwardEdge = new Edge <TV, TW>(verteces[directedEdge.TargetVertex.Value],
                                                                   verteces[directedEdge.OriginVertex.Value], currentFlow);
                    backwardEdge.SetAttribute(ATTR_DIRECTION, EdgeDirection.Backward);
                    builder.AddEdge(backwardEdge);
                }
            }

            return(builder.Build());
        }
Пример #3
0
        public static ImmutableArray <TNode> UniformCostSearch <TNode>(
            this IWeightedGraph <TNode> graph,
            TNode start,
            TNode goal) where TNode : notnull, IEquatable <TNode>
        {
            var frontier = new PriorityQueue <TNode, float>();

            frontier.Enqueue(start, 0);

            var cameFrom = new Dictionary <TNode, TNode>()
            {
                [start] = start
            };

            var costSoFar = new Dictionary <TNode, float>()
            {
                [start] = 0
            };

            while (frontier.TryDequeue(out var current, out _))
            {
                if (current.Equals(goal))
                {
                    break;
                }

                foreach (var next in graph.Neigbours(current))
                {
                    var newCost = costSoFar[current] + graph.Cost(current, next);
                    if (costSoFar.TryGetValue(next, out var nextCost) is false || newCost < nextCost)
                    {
                        costSoFar[next] = newCost;
                        var priority = newCost;
                        frontier.Enqueue(next, priority);
                        cameFrom[next] = current;
                    }
                }
            }

            return(ReconstructPath(start, goal, cameFrom));
        }
Пример #4
0
    /// <summary>
    /// Finds the cheapest path between two nodes of the specified graph.
    /// </summary>
    /// <typeparam name="T">The type of the graph's nodes.</typeparam>
    /// <param name="graph">A graph of nodes.</param>
    /// <param name="start">The starting node.</param>
    /// <param name="goal">The goal node to find a path to.</param>
    /// <param name="heuristic">An optional heuristic to determine the cost of moving from one node to another.</param>
    /// <returns>
    /// The minimum cost to traverse the graph from <paramref name="start"/> to <paramref name="goal"/>.
    /// </returns>
    public static long AStar <T>(IWeightedGraph <T> graph, T start, T goal, Func <T, T, long>?heuristic = default)
        where T : notnull
    {
        heuristic ??= (x, y) => graph.Cost(x, y);

        var frontier = new PriorityQueue <T, long>();

        frontier.Enqueue(start, 0);

        var costSoFar = new Dictionary <T, long>()
        {
            [start] = 0
        };

        while (frontier.Count > 0)
        {
            T current = frontier.Dequeue();

            if (current.Equals(goal))
            {
                break;
            }

            foreach (T next in graph.Neighbors(current))
            {
                long newCost = costSoFar[current] + heuristic(current, next);

                if (!costSoFar.TryGetValue(next, out long otherCost) || newCost < otherCost)
                {
                    costSoFar[next] = newCost;

                    long goalCost = heuristic(next, goal);
                    long priority = newCost + goalCost;

                    frontier.Enqueue(next, priority);
                }
            }
        }

        return(costSoFar.GetValueOrDefault(goal, long.MaxValue));
    }
Пример #5
0
        public LazyPrimeMST(IWeightedGraph <Weight> graph)
        {
            this.g      = graph;
            this.marked = new bool[graph.V()];
            this.ipq    = new MinHeap <Edge <Weight> >(graph.E()); // 边的个数
            this.path   = new List <Edge <Weight> >();

            //Lazy prime算法
            visit(0); //从0开始遍历

            while (!ipq.IsEmpty())
            {
                Edge <Weight> minEdge = ipq.ExtractMin();

                // 如果两个点在同一分区, 则边不符合跨区
                if (marked[minEdge.V()] == marked[minEdge.W()])
                {
                    continue;
                }
                // 把符合的边加入到最小生成树MST
                path.Add(minEdge);

                if (!marked[minEdge.V()])
                {
                    visit(minEdge.V());
                }
                else
                {
                    visit(minEdge.W());
                }
            }

            dynamic wt = default(Weight);

            for (int i = 0; i < path.Count; i++)
            {
                wt += path[i].Wt();
            }
            this.wt = (Weight)wt;
        }
Пример #6
0
        private static void UpdatePseudoBalance <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                         IVertex <TV> vertex,
                                                         Func <TW, TW, TW> combineValues,
                                                         Func <TW, TW, TW> substractValues,
                                                         TW zeroValue)
            where TV : IEquatable <TV> where TW : IComparable
        {
            TW pseudoBalance = zeroValue;

            // Add flow values of outgoing edges
            foreach (IWeightedEdge <TV, TW> edge in graph.GetEdgesOfVertex(vertex))
            {
                if (edge is IWeightedDirectedEdge <TV, TW> directedEdge)
                {
                    pseudoBalance = combineValues(pseudoBalance, edge.GetAttribute <TW>(Constants.FLOW));
                }
                else
                {
                    throw new GraphNotDirectedException();
                }
            }

            // Add flow values of incoming edges
            foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges())
            {
                if (edge is IWeightedDirectedEdge <TV, TW> directedEdge)
                {
                    if (directedEdge.TargetVertex == vertex)
                    {
                        pseudoBalance = substractValues(pseudoBalance, edge.GetAttribute <TW>(Constants.FLOW));
                    }
                }
                else
                {
                    throw new GraphNotDirectedException();
                }
            }
            vertex.SetAttribute(Constants.PSEUDO_BALANCE, pseudoBalance);
        }
Пример #7
0
        public static IWeightedGraph <TV, TW> BuildResidualGraph <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                          Func <TW, TW, TW> substractValues,
                                                                          Func <TW, TW> negateValue,
                                                                          TW zeroValue)
            where TV : IEquatable <TV> where TW : IComparable
        {
            // Build residual graph as done in Edmonds-Karp
            IWeightedGraph <TV, TW> residualGraph = EdmondsKarp.BuildResidualGraph(graph, substractValues, zeroValue);

            // Add costs
            foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges())
            {
                if (edge is IWeightedDirectedEdge <TV, TW> directedEdge)
                {
                    TW costs = edge.GetAttribute <TW>(Constants.COSTS);

                    // Add costs to forward edges
                    if (residualGraph.AreVertecesConnected(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value))
                    {
                        residualGraph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value)
                        .SetAttribute(Constants.COSTS, costs);
                    }

                    // Add negative costs to backward edges
                    if (residualGraph.AreVertecesConnected(directedEdge.TargetVertex.Value, directedEdge.OriginVertex.Value))
                    {
                        residualGraph.GetEdgeBetweenVerteces(directedEdge.TargetVertex.Value, directedEdge.OriginVertex.Value)
                        .SetAttribute(Constants.COSTS, negateValue(costs));
                    }
                }
                else
                {
                    throw new GraphNotDirectedException();
                }
            }

            // Done - return residual graph
            return(residualGraph);
        }
Пример #8
0
        public static bool search <T>(IWeightedGraph <T> graph, T start, T goal, out Dictionary <T, T> cameFrom)
        {
            var foundPath = false;

            cameFrom = new Dictionary <T, T>();
            cameFrom.Add(start, start);

            var costSoFar = new Dictionary <T, int>();
            var frontier  = new PriorityQueue <AStarNode <T> >(1000);

            frontier.Enqueue(new AStarNode <T>(start), 0);

            costSoFar[start] = 0;

            while (frontier.Count > 0)
            {
                var current = frontier.Dequeue();

                if (current.data.Equals(goal))
                {
                    foundPath = true;
                    break;
                }

                foreach (var next in graph.getNeighbors(current.data))
                {
                    var newCost = costSoFar[current.data] + graph.cost(current.data, next);
                    if (!costSoFar.ContainsKey(next) || newCost < costSoFar[next])
                    {
                        costSoFar[next] = newCost;
                        var priority = newCost + graph.heuristic(next, goal);
                        frontier.Enqueue(new AStarNode <T>(next), priority);
                        cameFrom[next] = current.data;
                    }
                }
            }

            return(foundPath);
        }
Пример #9
0
        private static int BreadthFirstSearch(
            IWeightedGraph graph,
            Vertex source,
            Vertex target,
            IWeightedGraph legalFlows,
            out IDictionary<Vertex, Vertex> path)
        {
            path = new Dictionary<Vertex, Vertex>();
            IDictionary<Vertex, int> pathCapacity = new Dictionary<Vertex, int>();

            path[source] = null; // make sure source is not rediscovered
            pathCapacity[source] = int.MaxValue;

            Queue<Vertex> queue = new Queue<Vertex>();
            queue.Enqueue(source);

            while(queue.Count > 0)
            {
                Vertex u = queue.Dequeue();
                foreach (Vertex v in graph.Neighbors(u))
                {
                    // if there is available capacity between u and v,
                    // ... and v is not seen before in search
                    if (graph.GetCapacity(u, v) - legalFlows.GetCapacity(u, v) > 0 &&
                        path.ContainsKey(v) == false)
                    {
                        path[v] = u;
                        pathCapacity[v] = Math.Min(
                            pathCapacity[u],
                            graph.GetCapacity(u, v) - legalFlows.GetCapacity(u ,v));

                        if (!v.Equals(target)) queue.Enqueue(v);
                        else return pathCapacity[target];
                    }
                }
            }

            return 0;
        }
Пример #10
0
        public PrimMST(IWeightedGraph <Weight> g)
        {
            this.g = g;
            marked = new bool[g.V()];
            ipq    = new IndexMinHeap <Weight>(g.V());

            edgeTo = new List <Edge <Weight> >(g.V());
            for (int i = 0; i < g.V(); i++)
            {
                edgeTo.Insert(i, null);
            }
            mst = new List <Edge <Weight> >();

            // Prim 算法
            visit(0);
            while (!ipq.IsEmpty())
            {
                // 去除最小的边
                int minV = ipq.GetMinIndex();
                ipq.ExtractMin();

                Edge <Weight> minEdge = edgeTo[minV];

                if (minEdge != null)
                {
                    mst.Add(minEdge);

                    visit(minV);
                }
            }

            dynamic weight = mst[0].Wt();

            for (int i = 1; i < mst.Count; i++)
            {
                weight += mst[i].Wt();
            }
            this.mstWeight = (Weight)weight;
        }
Пример #11
0
        public static bool Search <T>(IWeightedGraph <T> graph, T start, T goal, out Dictionary <T, T> cameFrom)
        {
            var foundPath = false;

            cameFrom = new Dictionary <T, T>();
            cameFrom.Add(start, start);

            var costSoFar = new Dictionary <T, float>();
            var frontier  = new SimplePriorityQueue <T>();

            costSoFar[start] = 0;

            frontier.Enqueue(start, 0);

            while (frontier.Count > 0)
            {
                var current = frontier.Dequeue();

                if (current.Equals(goal))
                {
                    foundPath = true;
                    break;
                }

                foreach (var next in graph.GetNeighbors(current))
                {
                    var newCost = costSoFar[current] + graph.Cost(current, next);
                    if (!costSoFar.ContainsKey(next) || newCost < costSoFar[next])
                    {
                        costSoFar[next] = newCost;
                        frontier.Enqueue(next, newCost);
                        cameFrom[next] = current;
                    }
                }
            }

            return(foundPath);
        }
Пример #12
0
        private void TestTspAlgorithm(IWeightedGraph <int, double> graph,
                                      TspAlgorithm algorithm,
                                      int expectedVerteces,
                                      int expectedEdges,
                                      double optimalTourCosts = 0.0,
                                      double precision        = 0.01)
        {
            IWeightedGraph <int, double> tour = null;

            // Compute tour with the chosen algorithm
            switch (algorithm)
            {
            case TspAlgorithm.NearestNeighbor:
                tour = NearestNeighbor.FindTour(graph);
                break;

            case TspAlgorithm.DoubleTree:
                tour = DoubleTree.FindTour(graph);
                break;

            case TspAlgorithm.BruteForce:
                tour = BruteForce.FindOptimalTour(graph, 0.0, double.MaxValue, (w1, w2) => w1 + w2);
                break;

            default:
                throw new NotSupportedException($"Testing TSP with the {algorithm} algorithm is currently not supported.");
            }

            // Check route for component count
            Assert.AreEqual(expectedVerteces, tour.VertexCount);
            Assert.AreEqual(expectedEdges, tour.GetAllEdges().Count());

            // For algorithms that find the optimal tour, check the optmial tour costs
            if (algorithm == TspAlgorithm.BruteForce)
            {
                AssertDoublesNearlyEqual(optimalTourCosts, tour.GetAllEdges().Sum(e => e.Weight), precision);
            }
        }
Пример #13
0
        private TimeSpan RunTest(string file, IWeightedGraph <int, double> graph, ALGORITHM algorithm)
        {
            Stopwatch sw = new Stopwatch();

            switch (algorithm)
            {
            case ALGORITHM.KRUSKAL:
                sw.Start();
                Algorithms.MinimumSpanningTree.Kruskal.FindMinimumSpanningTree(graph);
                sw.Stop();
                break;

            case ALGORITHM.PRIM:
                sw.Start();
                Algorithms.MinimumSpanningTree.Prim.FindMinimumSpanningTree(graph, 0, double.MaxValue);
                sw.Stop();
                break;
            }

            Logger.LogDebug($" - Computed MST for '{file}' using {algorithm}'s algorithm in {sw.Elapsed}.");

            return(sw.Elapsed);
        }
Пример #14
0
        public static IWeightedGraph <TV, TW> FindTour <TV, TW>(IWeightedGraph <TV, TW> graph) where TV : IEquatable <TV>
        {
            GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>();

            builder.AddVerteces(graph.GetAllVerteces().Select(v => v.Value));

            // Find minimum spanning tree
            IWeightedGraph <TV, TW> msp = Kruskal.FindMinimumSpanningTree(graph);

            // Connect verteces in the order of the MSP
            IVertex <TV> lastVertex = null;

            DepthFirstSearch.Traverse(msp, currentVertex =>
            {
                if (lastVertex != null)
                {
                    try
                    {
                        builder.AddEdge(lastVertex.Value, currentVertex.Value, graph.GetEdgeBetweenVerteces(lastVertex.Value, currentVertex.Value).Weight);
                    }
                    catch (VertecesNotConnectedException <TV> exception)
                    {
                        throw new GraphNotCompleteException("The graph is not complete.", exception);
                    }
                }
                lastVertex = currentVertex;
            });

            // Add closing edge
            IVertex <TV>           firstVertex = msp.GetFirstVertex();
            IWeightedEdge <TV, TW> closingEdge = graph.GetEdgeBetweenVerteces(lastVertex.Value, firstVertex.Value);

            builder.AddEdge(lastVertex.Value, firstVertex.Value, closingEdge.Weight);

            // Done!
            return(builder.Build());
        }
Пример #15
0
    public AStarSearch(IWeightedGraph <ICoordinates> graph, ICoordinates start, ICoordinates goal)
    {
        PriorityQueue <ICoordinates> frontier = new PriorityQueue <ICoordinates> ();

        frontier.enqueue(start, 0);
        cameFrom [start]  = start;
        costSoFar [start] = 0;

        while (frontier.getCount() > 0)
        {
            ICoordinates currentPosition = frontier.dequeue();

            if (currentPosition.Equals(goal))              // Break loop when find goal
            {
                break;
            }

            foreach (var nextPosition in graph.getNeighbors(currentPosition))
            {
                if (nextPosition == null)
                {
                    continue;
                }
                double cost = costSoFar[currentPosition]
                              + graph.getCost(currentPosition, nextPosition);

                if (!costSoFar.ContainsKey(nextPosition) ||
                    cost < costSoFar[nextPosition])                          // Enqueue when find new nearest path to nextPosition
                {
                    double priority = cost + heuristicFunction(currentPosition, nextPosition);
                    frontier.enqueue(nextPosition, priority);
                    cameFrom [nextPosition]  = currentPosition;
                    costSoFar [nextPosition] = cost;
                }
            }
        }
    }
Пример #16
0
        /// <summary>
        /// Finds the maximum flow between a source and target node and returns a new weighted graph
        /// representing the legal flows between vertices to generate the maximum flow.
        /// </summary>
        /// <remarks>
        /// Edmonds-Karp Max Flow Algorithm, based on my C# port (git.io/KewoqQ)
        /// of the Wikipedia psuedocode found here: (en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm)
        /// </remarks>
        /// <param name="graph">a weighted graph representing the flow network</param>
        /// <param name="source">the source node</param>
        /// <param name="target">the target node</param>
        /// <param name="legalFlows">an output graph representing legal flows</param>
        /// <returns>the maximum flow between source and target</returns>
        public static int FindMaxFlow(
            this IWeightedGraph graph,
            Vertex source,
            Vertex target,
            out IWeightedGraph legalFlows)
        {
            Graphs.Weighted.Mutable.IWeightedMutableGraph _legalFlows =
                new Graphs.Weighted.Mutable.AdjacencyMatrixGraph(graph.Vertices().Count());
            legalFlows = _legalFlows;
            foreach (Vertex v in graph.Vertices())
            {
                _legalFlows.AddVertex(v);
            }

            int f = 0; // initial flow is 0

            while (true)
            {
                IDictionary<Vertex, Vertex> path;
                int capacity = BreadthFirstSearch(graph, source, target, legalFlows, out path);

                if (capacity == 0) break;
                f += capacity;
                // backtrack search, and write flow
                Vertex v = target;

                while (!v.Equals(source))
                {
                    Vertex u = path[v];
                    _legalFlows.SetEdge(u, v, _legalFlows.GetCapacity(u, v) + capacity);
                    _legalFlows.SetEdge(v, u, _legalFlows.GetCapacity(v, u) - capacity);
                    v = u;
                }
            }

            return f;
        }
Пример #17
0
        public static IEnumerable <IEdge <TV> > FindMaxMatching <TV>(IGraph <TV> graph,
                                                                     ISet <IVertex <TV> > set1,
                                                                     ISet <IVertex <TV> > set2,
                                                                     TV superSourceValue,
                                                                     TV superTargetValue) where TV : IEquatable <TV>
        {
            // Build directed graph with super nodes and capacity 1
            IWeightedGraph <TV, int> graphWithSuperNodes = BuildGraphWithSuperNodesAndCapacity(graph, superSourceValue, superTargetValue, set1, set2, 1);
            IVertex <TV>             sourceNode          = graphWithSuperNodes.GetFirstMatchingVertex(v => v.Value.Equals(superSourceValue));
            IVertex <TV>             targetNode          = graphWithSuperNodes.GetFirstMatchingVertex(v => v.Value.Equals(superTargetValue));

            // Compute max flow in graph with super nodes
            IWeightedGraph <TV, int> maxFlow = EdmondsKarp.FindMaxFlow(graphWithSuperNodes,
                                                                       sourceNode,
                                                                       targetNode,
                                                                       (x, y) => x + y,
                                                                       (x, y) => x - y,
                                                                       0);

            // Add edges with flow to matching
            List <IEdge <TV> > matchings = new List <IEdge <TV> >();

            foreach (IVertex <TV> vertex in set1)
            {
                foreach (IEdge <TV> edge in graph.GetEdgesOfVertex(vertex))
                {
                    if (maxFlow.GetEdgeBetweenVerteces(vertex.Value, edge.ConnectedVertex(vertex).Value).Weight == 1)
                    {
                        matchings.Add(edge);
                    }
                }
            }

            // Done - return matching!
            return(matchings);
        }
Пример #18
0
        private void TestShortestPathsAlgorithm(IWeightedGraph <int, double> graph,
                                                IVertex <int> source,
                                                IVertex <int> target,
                                                double pathCosts,
                                                ShortestPathAlgorithm algorithm,
                                                double precision = 0.1)
        {
            IWeightedGraph <int, double> shortestPath = null;

            switch (algorithm)
            {
            case ShortestPathAlgorithm.Dijkstra:
                shortestPath = Dijkstra.FindShortestPath(graph, source, target, 0.0, double.MaxValue, (x, y) => x + y);
                break;

            case ShortestPathAlgorithm.BellmanFordMoore:
                shortestPath = BellmanFordMoore.FindShortestPath(graph, source, target, 0.0, double.MaxValue, (x, y) => x + y);
                break;

            default:
                throw new NotSupportedException($"Testing shortest path for the {algorithm} algorithm is currently not supported.");
            }
            AssertDoublesNearlyEqual(pathCosts, shortestPath.GetAllEdges().Sum(e => e.Weight), precision);
        }
Пример #19
0
            public AStarSearch(IWeightedGraph <GraphPoint> graph, GraphPoint start, GraphPoint goal)
            {
                start.wType = GraphPoint.WType.start;
                goal.wType  = GraphPoint.WType.end;
                var box = new Tools.PriorityQueue <GraphPoint>();

                box.Enqueue(start, 0);

                cameFrom[start]  = start;
                costSoFar[start] = 0;

                while (box.Count > 0)
                {
                    var current = box.Dequeue();

                    if (current.x == goal.x && current.y == goal.y)
                    {
                        cameFrom[goal] = current;
                        break;
                    }

                    foreach (var next in graph.Neighbors(current))
                    {
                        double newCost = costSoFar[current]
                                         + graph.Cost(current, next);
                        if (!costSoFar.ContainsKey(next) ||
                            newCost < costSoFar[next])
                        {
                            costSoFar[next] = newCost;
                            double priority = newCost + Heuristic(next, goal);
                            box.Enqueue(next, priority);
                            cameFrom[next] = current;
                        }
                    }
                }
            }
Пример #20
0
 public ShortestPathSearch(IWeightedGraph graph)
 {
     this.graph = graph;
 }
Пример #21
0
 public static IWeightedGraph <TV, TW> FindTour <TV, TW>(IWeightedGraph <TV, TW> graph) where TV : IEquatable <TV>
 {
     return(FindTour(graph, graph.GetFirstVertex()));
 }
Пример #22
0
 public DepthFirstSearch(IWeightedGraph graph)
 {
     this.graph = graph;
 }
 public BreadthFirstSearch(IWeightedGraph graph)
 {
     this.graph = graph;
 }
Пример #24
0
 /// <summary>
 /// Uses Bellman-Ford's algorithm to compute the shortest paths in a weighted graph. Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object containing the shortest paths. TWeight being the type of <see cref="short"/>.
 /// </summary>
 /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
 /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/> with TWeight being of type <see cref="short"/>.</param>
 /// <param name="source">The source vertex for which the shortest paths are computed.</param>
 /// <returns>Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> containing the shortest paths for the given source vertex. TWeight being the type of <see cref="short"/>.</returns>
 public static WeightedGraphShortestPaths <TVertex, short> BellmanFordShortestPaths <TVertex>(this IWeightedGraph <TVertex, short> graph, TVertex source)
     where TVertex : IComparable <TVertex>
 {
     return(BellmanFordShortestPaths(graph, source, (x, y) => (short)(x + y)));
 }
Пример #25
0
 /// <summary>
 /// Tries to compute the shortest paths in a weighted graph with the Bellman-Ford's algorithm. Returns true if successful; otherwise false.
 /// </summary>
 /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
 /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/> with TWeight being of type <see cref="short"/>.</param>
 /// <param name="source">The source vertex for which the shortest paths are computed.</param>
 /// <param name="shortestPaths">The <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object (TWeight being the type of <see cref="short"/>) that contains the shortest paths of the graph if the algorithm was successful; otherwise null.</param>
 /// <returns>Returns true if the shortest paths were successfully computed; otherwise false. Also returns false if the given source vertex does not belong to the graph.</returns>
 public static bool TryGetBellmanFordShortestPaths <TVertex>(this IWeightedGraph <TVertex, short> graph, TVertex source, out WeightedGraphShortestPaths <TVertex, short> shortestPaths)
     where TVertex : IComparable <TVertex>
 {
     return(TryGetBellmanFordShortestPaths(graph, source, out shortestPaths, (x, y) => (short)(x + y)));
 }
Пример #26
0
        /// <summary>
        /// Uses Bellman-Ford's algorithm to compute the shortest paths in a weighted graph. Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object containing the shortest paths.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param>
        /// <param name="source">The source vertex for which the shortest paths are computed.</param>
        /// <param name="weightAdder">The method corresponding to the <see cref="AddWeights{TWeight}"/> delegate used for calculating the sum of two edge weights.</param>
        /// <returns>Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> containing the shortest paths for the given source vertex.</returns>
        public static WeightedGraphShortestPaths <TVertex, TWeight> BellmanFordShortestPaths <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph, TVertex source, AddWeights <TWeight> weightAdder)
            where TVertex : IComparable <TVertex>
            where TWeight : IComparable <TWeight>
        {
            if (!graph.ContainsVertex(source))
            {
                throw new ArgumentException("Vertex does not belong to the graph!");
            }

            WeightedGraphShortestPaths <TVertex, TWeight> shortestPaths;

            if (TryGetBellmanFordShortestPaths(graph, source, out shortestPaths, weightAdder))
            {
                return(shortestPaths);
            }
            else
            {
                throw new InvalidOperationException("Negative weight cycle found!");
            }
        }
Пример #27
0
        /// <summary>
        /// Tries to compute the shortest paths in a weighted graph with the Bellman-Ford's algorithm. Returns true if successful; otherwise false.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param>
        /// <param name="source">The source vertex for which the shortest paths are computed.</param>
        /// <param name="shortestPaths">The <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object that contains the shortest paths of the graph if the algorithm was successful; otherwise null.</param>
        /// <param name="weightAdder">The method corresponding to the <see cref="AddWeights{TWeight}"/> delegate used for calculating the sum of two edge weights.</param>
        /// <returns>Returns true if the shortest paths were successfully computed; otherwise false. Also returns false if the given source vertex does not belong to the graph.</returns>
        public static bool TryGetBellmanFordShortestPaths <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph, TVertex source, out WeightedGraphShortestPaths <TVertex, TWeight> shortestPaths, AddWeights <TWeight> weightAdder)
            where TVertex : IComparable <TVertex>
            where TWeight : IComparable <TWeight>
        {
            shortestPaths = null;

            if (!graph.ContainsVertex(source))
            {
                return(false);
            }

            // A dictionary holding a vertex as key and as value a key-value pair of its previous vertex in the path(being the key) and the weight of the edge connecting them(being the value).
            var previousVertices = new Dictionary <TVertex, KeyValuePair <TVertex, TWeight> >();
            // The dictionary holding a vertex as key and as value a key-value pair holding the weight of the path from the source vertex(being the key) and the distance from the source vertex(being the value).
            var weightAndDistance = new Dictionary <TVertex, KeyValuePair <TWeight, int> >();

            // Add source vertex to computed weights and distances
            weightAndDistance.Add(source, new KeyValuePair <TWeight, int>(default(TWeight), 0));

            // Get all edges and sort them by their source and then by their destination vertex to create a consistent shortest paths output.
            var allEdges = graph.Edges.ToList();

            if (allEdges.Count > 0)
            {
                allEdges.QuickSort((x, y) =>
                {
                    int cmp = x.Source.CompareTo(y.Source);
                    if (cmp == 0)
                    {
                        cmp = x.Destination.CompareTo(y.Destination);
                    }
                    return(cmp);
                });
            }

            // We relax all edges n - 1 times and if at the n-th step a relaxation is needed we have a negative cycle
            int lastStep = graph.VerticesCount - 1;

            for (int i = 0; i < graph.VerticesCount; i++)
            {
                foreach (var edge in allEdges)
                {
                    var edgeSource      = edge.Source;
                    var edgeDestination = edge.Destination;
                    var edgeWeight      = edge.Weight;

                    // If we have computed the path to the the source vertex of the edge
                    if (weightAndDistance.ContainsKey(edgeSource))
                    {
                        var     wd          = weightAndDistance[edgeSource];
                        TWeight curWeight   = wd.Key;
                        int     curDistance = wd.Value;

                        // If the edge destination is the source we continue with the next edge
                        if (object.Equals(source, edgeDestination))
                        {
                            continue;
                        }

                        // Compute path weight
                        TWeight pathWeight;
                        if (curWeight == null)
                        {
                            pathWeight = edgeWeight;
                        }
                        else
                        {
                            pathWeight = weightAdder(curWeight, edgeWeight);
                        }

                        // If this path is longer than an already computed path we continue with the next edge
                        if (weightAndDistance.ContainsKey(edgeDestination))
                        {
                            int cmp = pathWeight.CompareTo(weightAndDistance[edgeDestination].Key);
                            if (cmp > 0)
                            {
                                continue;
                            }
                            else if (cmp == 0)// if path is equal to an already computed path
                            {
                                // we continue with the next edge only if the distance is bigger or equal
                                if (curDistance + 1 >= weightAndDistance[edgeDestination].Value)
                                {
                                    continue;
                                }
                                // if the distance is smaller we update the path with this one
                            }
                        }

                        if (i == lastStep)// if we need to relax on the last iteration we have a negative cycle
                        {
                            return(false);
                        }

                        // Else we save the path
                        previousVertices[edgeDestination]  = new KeyValuePair <TVertex, TWeight>(edgeSource, edgeWeight);
                        weightAndDistance[edgeDestination] = new KeyValuePair <TWeight, int>(pathWeight, curDistance + 1);
                    }
                }
            }

            // Remove source vertex from weight and distance dictionary
            weightAndDistance.Remove(source);

            shortestPaths = new WeightedGraphShortestPaths <TVertex, TWeight>(source, previousVertices, weightAndDistance);
            return(true);
        }
Пример #28
0
 public DepthFirstSearch(IWeightedGraph graph)
 {
     this.graph = graph;
 }
Пример #29
0
 public L[] Search(L start, L goal, IWeightedGraph <L, C> graph)
 {
     return(Search(start, goal, graph, defaultHeuristic));
 }
Пример #30
0
        /// <summary>
        /// Uses Kruskal's algorithm to find the minimum spanning tree of the undirected weighted graph. Returns a <see cref="WeightedALGraph{TVertex, TWeight}"/> representing the MST.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param>
        /// <returns>Returns a <see cref="WeightedALGraph{TVertex, TWeight}"/> representing the MST.</returns>
        public static WeightedALGraph <TVertex, TWeight> KruskalMST <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph)
            where TVertex : IComparable <TVertex>
            where TWeight : IComparable <TWeight>
        {
            if (graph.IsDirected)
            {
                throw new ArgumentException("Graph is directed!");
            }

            var mst = new WeightedALGraph <TVertex, TWeight>();

            // A dictionary of the added vertices to the MST and their tree identifiers (first vertex from the tree)
            var addedVertices = new Dictionary <TVertex, TVertex>();
            // Edge comparer for the edge sorting
            var edgeComparer = Comparer <IWeightedEdge <TVertex, TWeight> > .Create((x, y) =>
            {
                int cmp = 0;
                // null checking because TWeight can be null
                if (x.Weight == null)
                {
                    if (y.Weight == null)
                    {
                        cmp = -1;                   // change cmp to skip next comparisons
                    }
                    else
                    {
                        return(int.MinValue);
                    }
                }

                if (cmp == 0)// if Weights are not both null
                {
                    if (y.Weight == null)
                    {
                        return(int.MaxValue);
                    }
                    // normal check if both weights are not null
                    cmp = x.Weight.CompareTo(y.Weight);
                }
                else
                {
                    cmp = 0; // if both Weights were null, compare the kvp value
                }
                if (cmp == 0)
                {
                    cmp = x.Source.CompareTo(y.Source);
                }
                if (cmp == 0)
                {
                    cmp = x.Destination.CompareTo(y.Destination);
                }
                return(cmp);
            });

            var vertices = graph.Vertices.ToList();

            if (vertices.Count == 0)
            {
                return(mst);
            }

            mst.AddVertices(vertices);

            // Get edges
            var edges = graph.Edges.ToList();

            if (edges.Count == 0)
            {
                return(mst);
            }
            // Sort them
            edges.QuickSort(edgeComparer);

            for (int i = 0; i < edges.Count; i++)
            {
                var curEdge = edges[i];

                if (addedVertices.ContainsKey(curEdge.Source))
                {
                    if (addedVertices.ContainsKey(curEdge.Destination))// if both vertices are added to the MST
                    {
                        // Find tree roots
                        var srcRoot = FindTreeRoot(addedVertices, curEdge.Source);
                        var dstRoot = FindTreeRoot(addedVertices, curEdge.Destination);

                        // If vertices belong to the same tree we continue. Edge will create a cycle.
                        if (object.Equals(srcRoot, dstRoot))
                        {
                            continue;
                        }
                        else // if not add edge and connect the trees
                        {
                            // Add edge to MST
                            mst.AddEdge(curEdge.Source, curEdge.Destination, curEdge.Weight);
                            // Connect destination vertex tree with the source
                            addedVertices[curEdge.Destination] = srcRoot;
                            addedVertices[dstRoot]             = srcRoot;
                        }
                    }
                    else // if the source is added to the MST but not the destination
                    {
                        // Add edge to MST
                        mst.AddEdge(curEdge.Source, curEdge.Destination, curEdge.Weight);
                        // Find tree root
                        var srcRoot = FindTreeRoot(addedVertices, curEdge.Source);
                        // Add to the tree
                        addedVertices.Add(curEdge.Destination, srcRoot);
                    }
                }
                else // if the source is not added to the MST
                {
                    if (addedVertices.ContainsKey(curEdge.Destination))// if the destination is added
                    {
                        // Add edge to MST
                        mst.AddEdge(curEdge.Source, curEdge.Destination, curEdge.Weight);
                        // Find tree root
                        var dstRoot = FindTreeRoot(addedVertices, curEdge.Destination);
                        // Add to the tree
                        addedVertices.Add(curEdge.Source, dstRoot);
                    }
                    else// if both vertices are not added to the MST
                    {
                        // Add edge to MST
                        mst.AddEdge(curEdge.Source, curEdge.Destination, curEdge.Weight);
                        // Connect the vertices in a tree
                        addedVertices.Add(curEdge.Source, curEdge.Source);
                        addedVertices.Add(curEdge.Destination, curEdge.Source);
                    }
                }
            }

            // Return MST
            return(mst);
        }
Пример #31
0
 public DijkstraSP(IWeightedGraph <V> g)
 {
     _g = g;
 }
    public static List <TNode> ShortestPath <TNode>(
        IWeightedGraph <TNode> graph,
        TNode sourceNode,
        TNode targetNode,
        int maxiterations = 1000
        )
    {
        // Initialize values
        Dictionary <TNode, double> distance = new Dictionary <TNode, double>();
        Dictionary <TNode, TNode>  previous = new Dictionary <TNode, TNode>();

        // Instead of PriorityQueue
        List <TNode> localNodes = new List <TNode>();

        localNodes.Add(sourceNode);
        distance.Add(sourceNode, 0);

        // For iterations limit:
        int i = 0;

        while (localNodes.Count > 0 && i < maxiterations)
        {
            i++;
            // Return and remove best vertex (that is, connection with minimum distance
            TNode minNode = localNodes.OrderBy(n => distance[n]).First();
            localNodes.Remove(minNode);

            // Loop all connected nodes
            // foreach (TNode neighbor in connections[minNode])
            foreach (TNode neighbor in graph.Neighbors(minNode))
            {
                if (!distance.ContainsKey(neighbor))
                {
                    localNodes.Add(neighbor);
                    distance.Add(neighbor, double.PositiveInfinity);
                }

                // The positive distance between node and it's neighbor, added to the distance of the current node
                double dist = distance[minNode] + graph.Weight(minNode, neighbor);

                if (dist < distance[neighbor])
                {
                    distance[neighbor] = dist;
                    previous[neighbor] = minNode;
                }
            }

            // If we're at the target node, break
            if (graph.Equals(minNode, targetNode))
            {
                break;
            }
        }

        // Construct a list containing the complete path. We'll start by looking at the previous node of the target and then making our way to the beginning.
        // We'll reverse it to get a source->target list instead of the other way around. The source node is manually added.
        List <TNode> result = new List <TNode>();
        TNode        target = targetNode;

        while (previous.ContainsKey(target))
        {
            result.Add(target);
            target = previous[target];
        }
        result.Add(sourceNode);
        result.Reverse();


        return(result);
    }
Пример #33
0
 public List <string> search(IWeightedGraph graph, object startVertex, object endVertex)
 {
     return(depthFirstSearch(graph, startVertex, endVertex));
 }
Пример #34
0
 /// <summary>
 /// Initializes a new instance of the <see cref="BellmanFord"/> class.
 /// </summary>
 /// <param name="graph">The graph.</param>
 /// <param name="startNode">The start node.</param>
 public BellmanFordSearch([NotNull] IWeightedGraph graph, uint startNode)
     : this(graph, startNode, startNode)
 {
 }
 public ShortestPathSearch(IWeightedGraph graph)
 {
     this.graph = graph;
 }
Пример #36
0
        /**
         * Finds a minimum spanning tree in the graph.
         *
         * @note The MST is computed using the Prim's (also knows as DJP)
         * algorithm.
         * TODO: describe the algorithm
         *
         * @param mst                   Unweighted tree instance that will become
         *                              an MST in this method. The MST instance must
         *                              already contain all the original's graph
         *                              vertices.
         *
         * @return The weighted graph instance representing the MST. Note
         * that NULL is returned if the graph is disconnected (in other
         * words, there is not path from any given vertex to all other
         * vertices in the graph).
         *
         * @throws InvalidOperationException if graph is empty.
         */
        protected IWeightedGraph <VertexT> FindMinimumSpanningTree(IWeightedGraph <VertexT> mst)
        {
            if (Size == 0)
            {
                // It is illegal to call this method on an empty graph
                throw new InvalidOperationException();
            }

            // Priority queue that orders the edges in ascending order
            // by their weight. The next edge to place into MST is
            // taken from the priority queue.
            ArrayHeap <Edge> priority_queue =
                new ArrayHeap <Edge>(
                    Size,
                    (Edge edge_1, Edge edge_2) =>
            {
                // TODO: floats shouldn't be compared like this.
                if (edge_1.Weight < edge_2.Weight)
                {
                    return(-1);
                }
                else if (edge_1.Weight > edge_2.Weight)
                {
                    return(1);
                }
                else
                {
                    return(0);
                }
            });

            // A vertex is 'marked' once an edge ending in that vertex
            // has been added to MST, that is once vertex becomes part
            // of the MST. This helps ensure that we never add two edges
            // that end in the same vertex, which in turn makes sure
            // that generated graph is in fact a MST.
            BitArray marked_vertices = new BitArray(Size, false);

            marked_vertices[0] = true;

            // The vertex whose outward edges will be processed next
            int vertex_index = 0;

            // The following loop will run Size - 1 times, as we need
            // to select Size - 1 edges
            for (int i = 1; i < Size; ++i)
            {
                for (int column = 0; column < Size; ++column)
                {
                    float?edge_value = Edges.GetEdge(vertex_index, column);
                    if (edge_value != null && !marked_vertices[column])
                    {
                        // Add this edge to the priority queue
                        priority_queue.Insert(new Edge(vertex_index, column, edge_value.Value));
                    }
                }

                // Find the next edge to insert to the MST. We cannot simply pick
                // an edge at the head of the priority queue because the end
                // vertex of that edge might already be 'marked', hence edges
                // towards it must not be considered
                Edge min_weight_edge = null;
                do
                {
                    if (priority_queue.IsEmpty)
                    {
                        // This means that we're unable to reach all vertices
                        // of the graph (disconnected graph). Return NULL.
                        return(null);
                    }

                    min_weight_edge = priority_queue.Remove();
                } while (marked_vertices[min_weight_edge.EndVertex]);

                // Add the edge to the MST
                mst.AddEdge(
                    min_weight_edge.StartVertex,
                    min_weight_edge.EndVertex,
                    min_weight_edge.Weight);

                // 'Mark' the end vertex of the newly added edge
                marked_vertices[min_weight_edge.EndVertex] = true;

                // The next vertex whose outward edges will be processed is
                // the end vertex of the edge we just added to MST
                vertex_index = min_weight_edge.EndVertex;
            }

            return(mst);
        }