예제 #1
0
파일: EdmondsKarp.cs 프로젝트: alex-c/Graft
        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());
        }
예제 #2
0
        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();
            }
        }
예제 #3
0
파일: EdmondsKarp.cs 프로젝트: alex-c/Graft
        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());
        }