/// <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); } }
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()); }
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)); }
/// <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)); }
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; }
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); }
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); }
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); }
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; }
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; }
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); }
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); } }
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); }
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()); }
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; } } } }
/// <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; }
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); }
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); }
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; } } } }
public ShortestPathSearch(IWeightedGraph graph) { this.graph = graph; }
public static IWeightedGraph <TV, TW> FindTour <TV, TW>(IWeightedGraph <TV, TW> graph) where TV : IEquatable <TV> { return(FindTour(graph, graph.GetFirstVertex())); }
public DepthFirstSearch(IWeightedGraph graph) { this.graph = graph; }
public BreadthFirstSearch(IWeightedGraph graph) { this.graph = graph; }
/// <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))); }
/// <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))); }
/// <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!"); } }
/// <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); }
public L[] Search(L start, L goal, IWeightedGraph <L, C> graph) { return(Search(start, goal, graph, defaultHeuristic)); }
/// <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); }
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); }
public List <string> search(IWeightedGraph graph, object startVertex, object endVertex) { return(depthFirstSearch(graph, startVertex, endVertex)); }
/// <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) { }
/** * 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); }