public static IWeightedGraph <TV, TW> FindTour <TV, TW>(IWeightedGraph <TV, TW> graph, IVertex <TV> source) where TV : IEquatable <TV> { GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(); // Starting point IVertex <TV> currentVertex = source; builder.AddVertex(source.Value); // Track which verteces have already been added to the tour, and how many edges have already been used HashSet <TV> visitedVerteces = new HashSet <TV>() { source.Value }; int edgesUsed = 0; // Find and use minimum non-used edge leading from each vertex while (edgesUsed < graph.VertexCount) { // Last edge, select edge back to start if (edgesUsed == graph.VertexCount - 1) { try { IWeightedEdge <TV, TW> closingEdge = graph.GetEdgeBetweenVerteces(currentVertex, source); builder.AddEdge(currentVertex.Value, source.Value, closingEdge.Weight); } catch (VertecesNotConnectedException <TV> exception) { throw new GraphNotCompleteException("The NearestNeighbor algorithm expects the input graph to be complete!", exception); } } else { IWeightedEdge <TV, TW> minEdge = graph.GetEdgesOfVertex(currentVertex) .Where(e => !visitedVerteces.Contains(e.ConnectedVertex(currentVertex).Value)) .OrderBy(e => e.Weight) .FirstOrDefault(); if (minEdge == null) { throw new GraphNotCompleteException("The NearestNeighbor algorithm expects the input graph to be complete!"); } // Get target vertex and update current vertex IVertex <TV> target = minEdge.ConnectedVertex(currentVertex); currentVertex = target; // Update tracking visitedVerteces.Add(target.Value); // Update result graph builder.AddVertex(target.Value); builder.AddEdge(source.Value, target.Value, minEdge.Weight); } edgesUsed++; } // Done: used n-1 edges for n verteces return(builder.Build()); }
private static void RelaxEdge <TV, TW>(Dictionary <IVertex <TV>, TW> distanceMap, Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor, IVertex <TV> sourceVertex, IVertex <TV> targetVertex, TW weight, IWeightedEdge <TV, TW> edge, Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable { if (combineCosts(distanceMap[sourceVertex], weight).CompareTo(distanceMap[targetVertex]) < 0) { distanceMap[targetVertex] = combineCosts(distanceMap[sourceVertex], weight); predecessor[targetVertex] = edge; } }
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 static IWeightedGraph <TV, TW> FindShortestPath <TV, TW>(IWeightedGraph <TV, TW> graph, IVertex <TV> source, IVertex <TV> target, TW zeroValue, TW maxValue, Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable { HashSet <IVertex <TV> > visitedVerteces = new HashSet <IVertex <TV> >(); IPriorityQueue <IVertex <TV>, TW> vertecesToVisit = new NaivePriorityQueue <IVertex <TV>, TW>(); Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor = new Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> >(); // Initialize queue and predecessor map foreach (IVertex <TV> vertex in graph.GetAllVerteces()) { vertecesToVisit.Enqueue(vertex, maxValue); predecessor.Add(vertex, null); } vertecesToVisit.UpdatePriority(source, zeroValue); // Continue as long as there are verteces to visit IVertex <TV> currentVertex = null; TW currentCosts = zeroValue; while (!vertecesToVisit.Empty) { // Get the closest next vertex (currentVertex, currentCosts) = vertecesToVisit.Dequeue(); // Check whether we reached our target if (currentVertex == target) { break; } visitedVerteces.Add(currentVertex); // If not, discover the next verteces that can be visited foreach (IWeightedEdge <TV, TW> edge in graph.GetEdgesOfVertex(currentVertex)) { if (edge.Weight.CompareTo(zeroValue) < 0) { throw new NegativeEdgeWeightException(); } IVertex <TV> connectedVertex = edge.ConnectedVertex(currentVertex); if (!visitedVerteces.Contains(connectedVertex)) { TW newCosts = combineCosts(currentCosts, edge.Weight); if (newCosts.CompareTo(vertecesToVisit.GetPriorityOf(connectedVertex)) < 0) { vertecesToVisit.UpdatePriority(connectedVertex, newCosts); predecessor[connectedVertex] = edge; } } } } // If we reached the target vertex, build result graph if (currentVertex == target) { GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(true).AddVertex(target.Value); while (currentVertex != source) { IWeightedEdge <TV, TW> pathEdge = predecessor[currentVertex]; IVertex <TV> previousVertex = pathEdge.ConnectedVertex(currentVertex); builder .AddVertex(previousVertex.Value) .AddEdge(previousVertex.Value, currentVertex.Value, pathEdge.Weight); currentVertex = previousVertex; } return(builder.Build()); } else { throw new VertexNotReachableException <TV>(target); } }
public static IWeightedGraph <TV, TW> FindShortestPath <TV, TW>(IWeightedGraph <TV, TW> graph, IVertex <TV> source, IVertex <TV> target, TW zeroValue, TW maxValue, Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable { Dictionary <IVertex <TV>, TW> distance = new Dictionary <IVertex <TV>, TW>(); Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor = new Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> >(); // Initialize distance and predecessor maps foreach (IVertex <TV> vertex in graph.GetAllVerteces()) { distance.Add(vertex, maxValue); predecessor.Add(vertex, null); } distance[source] = zeroValue; // Relax edges repeatedly IEnumerable <IWeightedEdge <TV, TW> > edges = graph.GetAllEdges(); for (int i = 0; i < graph.VertexCount - 1; i++) { foreach (IWeightedEdge <TV, TW> edge in edges) { if (graph.IsDirected) { try { IWeightedDirectedEdge <TV, TW> directedEdge = (IWeightedDirectedEdge <TV, TW>)edge; RelaxEdge(distance, predecessor, directedEdge.OriginVertex, directedEdge.TargetVertex, directedEdge.Weight, directedEdge, combineCosts); } catch { throw new Exception("Failed casting edge to directed edge for directed graph."); } } else { IVertex <TV> sourceVertex = edge.Verteces.First(); IVertex <TV> targetVertex = edge.ConnectedVertex(sourceVertex); RelaxEdge(distance, predecessor, sourceVertex, targetVertex, edge.Weight, edge, combineCosts); RelaxEdge(distance, predecessor, targetVertex, sourceVertex, edge.Weight, edge, combineCosts); } } } // Check for negative - weight cycles foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges()) { if (graph.IsDirected) { IWeightedDirectedEdge <TV, TW> directedEdge = (IWeightedDirectedEdge <TV, TW>)edge; CheckForNegativeCycles(distance, directedEdge.OriginVertex, directedEdge.TargetVertex, directedEdge.Weight, combineCosts); } else { IVertex <TV> sourceVertex = edge.Verteces.First(); IVertex <TV> targetVertex = edge.ConnectedVertex(sourceVertex); CheckForNegativeCycles(distance, sourceVertex, targetVertex, edge.Weight, combineCosts); CheckForNegativeCycles(distance, targetVertex, sourceVertex, edge.Weight, combineCosts); } } // Build and output path IVertex <TV> currentVertex = target; GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(true).AddVertex(target.Value); while (currentVertex != source) { IWeightedEdge <TV, TW> pathEdge = predecessor[currentVertex]; IVertex <TV> previousVertex = pathEdge.ConnectedVertex(currentVertex); builder .AddVertex(previousVertex.Value) .AddEdge(previousVertex.Value, currentVertex.Value, pathEdge.Weight); currentVertex = previousVertex; } return(builder.Build()); }
/// <summary> /// Builds the minimum spanning tree of a given graph. /// </summary> /// <typeparam name="TV">Type of the graph vertex values.</typeparam> /// <typeparam name="TW">Type of the graph edge weights.</typeparam> /// <param name="graph">The graph got which to build the minimum spanning tree.</param> /// <returns>Returns the minimum spanning tree of the given graph.</returns> public static IWeightedGraph <TV, TW> FindMinimumSpanningTree <TV, TW>(IWeightedGraph <TV, TW> graph, TW min, TW max) where TV : IEquatable <TV> where TW : IComparable { // Builder used to incrementally build the target minimum spanning tree GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(); // Get all verteces and edges of graph IEnumerable <IVertex <TV> > verteces = graph.GetAllVerteces(); IEnumerable <IWeightedEdge <TV, TW> > edges = graph.GetAllEdges(); // TODO: replace with more performant priority queue implementation // Track minimum known cost to connect to target vertex IPriorityQueue <TV, TW> vertexCosts = new NaivePriorityQueue <TV, TW>(); // Track target vertex and edge connecting to target vertex with minimum known cost Dictionary <TV, IVertex <TV> > vertexValue = new Dictionary <TV, IVertex <TV> >(); Dictionary <TV, IWeightedEdge <TV, TW> > vertexEdges = new Dictionary <TV, IWeightedEdge <TV, TW> >(); // Initialize vertex costs with all costs set to max foreach (IVertex <TV> vertex in verteces) { vertexCosts.Enqueue(vertex.Value, max); vertexValue.Add(vertex.Value, vertex); vertexEdges.Add(vertex.Value, null); } // Set starting vertex vertexCosts.UpdatePriority(verteces.First().Value, min); // While there are verteces left to add, select vertex with smallest cost while (!vertexCosts.Empty) { // Get and remove vertex with smallest cost TV minCost = vertexCosts.Dequeue().Item1; // For easier handling, get vertex and edge IVertex <TV> vertex = vertexValue[minCost]; IWeightedEdge <TV, TW> edge = vertexEdges[minCost]; // Add vertex and edge to target MST builder.AddVertex(vertex.Value); if (edge != null) { builder.AddEdge(vertex.Value, edge.ConnectedVertex(vertex.Value).Value, edge.Weight); } // Update vertex cost for adjacent verteces and store edges foreach (IWeightedEdge <TV, TW> connectedEdge in graph.GetEdgesOfVertex(vertex)) { // Ignore edges leading to verteces already added to the MST IVertex <TV> targetVertex = connectedEdge.ConnectedVertex(vertex); if (vertexCosts.Contains(targetVertex.Value) && connectedEdge.Weight.CompareTo(vertexCosts.GetPriorityOf(targetVertex.Value)) < 0) { vertexCosts.UpdatePriority(targetVertex.Value, connectedEdge.Weight); vertexEdges[targetVertex.Value] = connectedEdge; } } } // All verteces added to MST - done! return(builder.Build()); }
private static void RecursivelyTryAllTours <TV, TW>(IWeightedGraph <TV, TW> graph, IVertex <TV> currentVertex, IVertex <TV> startingVertex, TW currentCosts, HashSet <IVertex <TV> > visitedVerteces, HashSet <IWeightedEdge <TV, TW> > usedEdges, ref HashSet <IWeightedEdge <TV, TW> > minTour, ref TW minCosts, Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable { // Check whether we can complete a tour if (usedEdges.Count == graph.VertexCount - 1) { try { // Add closing edge to complete tour IWeightedEdge <TV, TW> closingEdge = graph.GetEdgeBetweenVerteces(currentVertex, startingVertex); usedEdges.Add(closingEdge); // Check tour costs and compare to current min tour/costs TW tourCosts = combineCosts(currentCosts, closingEdge.Weight); if (tourCosts.CompareTo(minCosts) < 0) { minTour = new HashSet <IWeightedEdge <TV, TW> >(usedEdges); minCosts = tourCosts; } // Pop closing edge usedEdges.Remove(closingEdge); } catch (VertecesNotConnectedException <TV> exception) { throw new GraphNotCompleteException("The graph is not complete!", exception); } } // Continue building tours using connected verteces else { visitedVerteces.Add(currentVertex); // Check all connected verteces foreach (IWeightedEdge <TV, TW> edge in graph.GetEdgesOfVertex(currentVertex)) { IVertex <TV> targetVertex = edge.ConnectedVertex(currentVertex); if (!visitedVerteces.Contains(targetVertex)) { usedEdges.Add(edge); // Comput new tour costs and branch and bound TW newCosts = combineCosts(currentCosts, edge.Weight); if (newCosts.CompareTo(minCosts) < 0) { RecursivelyTryAllTours(graph, targetVertex, startingVertex, newCosts, visitedVerteces, usedEdges, ref minTour, ref minCosts, combineCosts); } // Pop last edge on the way up usedEdges.Remove(edge); } } // Pop last vertex on the way up visitedVerteces.Remove(currentVertex); } }
/// <summary> Сравниваем </summary> public bool Equals(IWeightedEdge other) { return(Equals((IEdge)other)); }
public static IWeightedGraph <TV, TW> FindCostMinimalFlow <TV, TW>(IWeightedGraph <TV, TW> graph, TV superSourceValue, TV superTargetValue, Func <TW, TW, TW> combineValues, Func <TW, TW, TW> substractValues, Func <TW, TW> negateValue, TW zeroValue, TW maxValue) where TV : IEquatable <TV> where TW : IComparable { // Add initial flow values to all graph edges: 0 or maximum edge capacity for edges with negative costs foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges()) { if (edge.GetAttribute <TW>(Constants.COSTS).CompareTo(zeroValue) < 0) { edge.SetAttribute(Constants.FLOW, edge.Weight); } else { edge.SetAttribute(Constants.FLOW, zeroValue); } } // Set pseudo-balances and track pseudo-nodes List <IVertex <TV> > pseudoSources = new List <IVertex <TV> >(); List <IVertex <TV> > pseudoTargets = new List <IVertex <TV> >(); foreach (IVertex <TV> vertex in graph.GetAllVerteces()) { // Compute pseudo balances UpdatePseudoBalance(graph, vertex, combineValues, substractValues, zeroValue); // Track pseudo-sources and pseudo-targets if (vertex.GetAttribute <TW>(Constants.BALANCE).CompareTo(vertex.GetAttribute <TW>(Constants.PSEUDO_BALANCE)) > 0) { pseudoSources.Add(vertex); } else if (vertex.GetAttribute <TW>(Constants.BALANCE).CompareTo(vertex.GetAttribute <TW>(Constants.PSEUDO_BALANCE)) < 0) { pseudoTargets.Add(vertex); } } while (pseudoSources.Any() && pseudoTargets.Any()) { // Build residual graph IWeightedGraph <TV, TW> residualGraph = CycleCanceling.BuildResidualGraph(graph, substractValues, negateValue, zeroValue); // Select pseudo-source IVertex <TV> pseudoSource = pseudoSources.First(); // Attempt to find a pseudo-target reachable from the pseudo-source in the residual graph IVertex <TV> pseudoTarget = null; IWeightedGraph <TV, TW> pathToTarget = null; foreach (IVertex <TV> currentPseudoTarget in pseudoTargets) { try { IWeightedGraph <TV, TW> bfmGraph = BuildGraphForBellmanFordMoore(residualGraph); IVertex <TV> bfmSource = bfmGraph.GetFirstMatchingVertex(v => v.Value.Equals(pseudoSource.Value)); IVertex <TV> bfmTarget = bfmGraph.GetFirstMatchingVertex(v => v.Value.Equals(currentPseudoTarget.Value)); IWeightedGraph <TV, TW> pathToCurrentTarget = BellmanFordMoore.FindShortestPath(bfmGraph, bfmSource, bfmTarget, zeroValue, maxValue, combineValues); if (pathToCurrentTarget != null) { pseudoTarget = currentPseudoTarget; pathToTarget = pathToCurrentTarget; break; } } catch (Exception) { /* silent */ } } // Abort if no pair of reachable pseudo-nodes was found if (pseudoTarget == null) { break; } // Determine max possible augmenting flow value TW minPathCapacity = maxValue; foreach (IWeightedEdge <TV, TW> edge in pathToTarget.GetAllEdges()) { if (edge is IWeightedDirectedEdge <TV, TW> directedEdge) { IWeightedEdge <TV, TW> residualEdge = residualGraph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value); minPathCapacity = MinValue(new TW[] { minPathCapacity, residualEdge.Weight }); } else { throw new GraphNotDirectedException(); } } TW sourceRestBalance = substractValues(pseudoSource.GetAttribute <TW>(Constants.BALANCE), pseudoSource.GetAttribute <TW>(Constants.PSEUDO_BALANCE)); TW targetRestBalance = substractValues(pseudoTarget.GetAttribute <TW>(Constants.PSEUDO_BALANCE), pseudoTarget.GetAttribute <TW>(Constants.BALANCE)); TW augmentingFlow = MinValue(new TW[] { minPathCapacity, sourceRestBalance, targetRestBalance }); // Update b-flow in original graph foreach (IWeightedEdge <TV, TW> edge in pathToTarget.GetAllEdges()) { if (edge is IWeightedDirectedEdge <TV, TW> directedEdge) { IWeightedEdge <TV, TW> residualEdge = residualGraph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value); if (residualEdge.GetAttribute <EdgeDirection>(Constants.DIRECTION) == EdgeDirection.Forward) { IWeightedEdge <TV, TW> graphEdge = graph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value); graphEdge.SetAttribute(Constants.FLOW, combineValues(graphEdge.GetAttribute <TW>(Constants.FLOW), augmentingFlow)); } else { IWeightedEdge <TV, TW> graphEdge = graph.GetEdgeBetweenVerteces(directedEdge.TargetVertex.Value, directedEdge.OriginVertex.Value); graphEdge.SetAttribute(Constants.FLOW, substractValues(graphEdge.GetAttribute <TW>(Constants.FLOW), augmentingFlow)); } } else { throw new GraphNotDirectedException(); } } // Remove pseudo-nodes (from tracking) if they will have their balance satisfied if (augmentingFlow.Equals(sourceRestBalance)) { pseudoSources.Remove(pseudoSource); } if (augmentingFlow.Equals(targetRestBalance)) { pseudoTargets.Remove(pseudoTarget); } // Update pseudo-balances of used pseudo-source and pseudo-target UpdatePseudoBalance(graph, pseudoSource, combineValues, substractValues, zeroValue); UpdatePseudoBalance(graph, pseudoTarget, combineValues, substractValues, zeroValue); } // Check balances if (!graph.GetAllVerteces().All(v => v.GetAttribute <TW>(Constants.BALANCE).Equals(v.GetAttribute <TW>(Constants.PSEUDO_BALANCE)))) { throw new NoBFlowException(); } // If we reach this, a valid b-flow was found! return(graph); }