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 { // Build graph with super nodes IWeightedGraph <TV, TW> graphWithSuperNodes = BuildGraphWithSuperNodes(graph, superSourceValue, superTargetValue, negateValue); // Get max flow in graph with super nodes IWeightedGraph <TV, TW> maxFlow = EdmondsKarp.FindMaxFlow(graphWithSuperNodes, graphWithSuperNodes.GetFirstMatchingVertex(v => v.Value.Equals(superSourceValue)), graphWithSuperNodes.GetFirstMatchingVertex(v => v.Value.Equals(superTargetValue)), combineValues, substractValues, zeroValue); TW maxFlowValue = FlowValue(maxFlow, superSourceValue, combineValues, zeroValue); // Check for existance of a b-flow IEnumerable <IVertex <TV> > sources = graph.GetAllMatchingVerteces(v => v.GetAttribute <double>(Constants.BALANCE) > 0); IEnumerable <IVertex <TV> > targets = graph.GetAllMatchingVerteces(v => v.GetAttribute <double>(Constants.BALANCE) < 0); TW sourcesBalance = zeroValue; TW targetsBalance = zeroValue; foreach (IVertex <TV> source in sources) { sourcesBalance = combineValues(sourcesBalance, source.GetAttribute <TW>(Constants.BALANCE)); } foreach (IVertex <TV> target in targets) { targetsBalance = combineValues(targetsBalance, target.GetAttribute <TW>(Constants.BALANCE)); } if (maxFlowValue.Equals(sourcesBalance) && maxFlowValue.Equals(negateValue(targetsBalance))) { // Copy flow values from graph with super nodes to original graph foreach (IWeightedEdge <TV, TW> edge in graphWithSuperNodes.GetAllEdges()) { if (edge is IWeightedDirectedEdge <TV, TW> directedEdge) { if (!directedEdge.OriginVertex.Value.Equals(superSourceValue) && !directedEdge.TargetVertex.Value.Equals(superTargetValue)) { graph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value) .SetAttribute(Constants.FLOW, edge.GetAttribute <TW>(Constants.FLOW)); } } else { throw new GraphNotDirectedException(); } } bool modifyingCycleLeft; do { // Build residual graph IWeightedGraph <TV, TW> residualGraph = BuildResidualGraph(graph, substractValues, negateValue, zeroValue); // Prepare graph for BellmanFordMoore IWeightedGraph <TV, TW> bfmGraph = BuildGraphForBellmanFordMoore(residualGraph, superSourceValue, zeroValue); // Attempt to find modifying cycle IVertex <TV> bfmSuperSource = bfmGraph.GetFirstMatchingVertex(v => v.Value.Equals(superSourceValue)); if (modifyingCycleLeft = BellmanFordMoore.TryFindNegativeCycle(bfmGraph, bfmSuperSource, zeroValue, maxValue, combineValues, out IEnumerable <IWeightedDirectedEdge <TV, TW> > cycle)) { // Get minimum capacity of the cycle in the residual graph List <IWeightedDirectedEdge <TV, TW> > rgCycle = new List <IWeightedDirectedEdge <TV, TW> >(); foreach (IWeightedDirectedEdge <TV, TW> edge in cycle) { rgCycle.Add((IWeightedDirectedEdge <TV, TW>)residualGraph.GetEdgeBetweenVerteces(edge.OriginVertex.Value, edge.TargetVertex.Value)); } TW minCycleCapacity = rgCycle.Min(e => e.Weight); // Modify b-flow along cycle foreach (IWeightedDirectedEdge <TV, TW> edge in rgCycle) { if (edge.GetAttribute <EdgeDirection>(Constants.DIRECTION) == EdgeDirection.Forward) { IWeightedDirectedEdge <TV, TW> graphEdge = (IWeightedDirectedEdge <TV, TW>)graph.GetEdgeBetweenVerteces(edge.OriginVertex.Value, edge.TargetVertex.Value); graphEdge.SetAttribute(Constants.FLOW, combineValues(graphEdge.GetAttribute <TW>(Constants.FLOW), minCycleCapacity)); } else { IWeightedDirectedEdge <TV, TW> graphEdge = (IWeightedDirectedEdge <TV, TW>)graph.GetEdgeBetweenVerteces(edge.TargetVertex.Value, edge.OriginVertex.Value); graphEdge.SetAttribute(Constants.FLOW, substractValues(graphEdge.GetAttribute <TW>(Constants.FLOW), minCycleCapacity)); } } } }while (modifyingCycleLeft); // Return same graph return(graph); } else { throw new NoBFlowException(); } }
public static IWeightedGraph <TV, TW> FindMaxFlow <TV, TW>(IWeightedGraph <TV, TW> graph, IVertex <TV> source, IVertex <TV> target, Func <TW, TW, TW> combineFlowValues, Func <TW, TW, TW> substractFlowValues, TW zeroValue) where TV : IEquatable <TV> where TW : IComparable { // Set initial flow to 0 foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges()) { edge.SetAttribute(ATTR_FLOW, zeroValue); } // Augment flow until there are not augmenting paths in the residual graph left IWeightedGraph <TV, TW> residualGraph = null; bool anyPathLeft = true; do { // Build residual graph residualGraph = BuildResidualGraph(graph, substractFlowValues, zeroValue); // Find (s,t)-path in residual graph IVertex <TV> residualSource = residualGraph.GetFirstMatchingVertex(v => v.Value.Equals(source.Value)); IVertex <TV> residualTarget = residualGraph.GetFirstMatchingVertex(v => v.Value.Equals(target.Value)); if (TryFindPath(residualGraph, residualSource, residualTarget, out List <IWeightedEdge <TV, TW> > path)) { // Augment f according to the found path TW augmentingFlowValue = path.Min(e => e.Weight); foreach (IWeightedDirectedEdge <TV, TW> edge in path) { // Add or substract augmenting flow value from current value depending on edge direction if (edge.GetAttribute <EdgeDirection>(ATTR_DIRECTION) == EdgeDirection.Forward) { IWeightedDirectedEdge <TV, TW> graphEdge = (IWeightedDirectedEdge <TV, TW>) graph.GetEdgeBetweenVerteces(edge.OriginVertex.Value, edge.TargetVertex.Value); TW currentFlow = graphEdge.GetAttribute <TW>(ATTR_FLOW); graphEdge.SetAttribute(ATTR_FLOW, combineFlowValues(currentFlow, augmentingFlowValue)); } else { IWeightedDirectedEdge <TV, TW> graphEdge = (IWeightedDirectedEdge <TV, TW>) graph.GetEdgeBetweenVerteces(edge.TargetVertex.Value, edge.OriginVertex.Value); TW currentFlow = graphEdge.GetAttribute <TW>(ATTR_FLOW); graphEdge.SetAttribute(ATTR_FLOW, substractFlowValues(currentFlow, augmentingFlowValue)); } } } else { // Terminate if there is no (s,t)-path left in the residual graph anyPathLeft = false; } } while (anyPathLeft); // Build copy of input graph with max flow as edge weight GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(true) .AddVerteces(graph.GetAllVerteces().Select(v => v.Value)); foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges()) { IWeightedDirectedEdge <TV, TW> graphEdge = (IWeightedDirectedEdge <TV, TW>)edge; builder.AddEdge(graphEdge.OriginVertex.Value, graphEdge.TargetVertex.Value, graphEdge.GetAttribute <TW>(ATTR_FLOW)); } return(builder.Build()); }