public void EdmondsKarpMaxFlow_NegativeCapacity_Throws() { const int source = 1; const int sink = 4; var graph = new AdjacencyGraph <int, TaggedEdge <int, double> >(); // TaggedEdge.Tag is the capacity of the edge graph.AddVerticesAndEdgeRange(new[] { new TaggedEdge <int, double>(1, 2, 3), new TaggedEdge <int, double>(1, 4, 4), new TaggedEdge <int, double>(2, 3, -1), new TaggedEdge <int, double>(3, 4, 1) }); EdgeFactory <int, TaggedEdge <int, double> > edgeFactory = (sourceNode, targetNode) => new TaggedEdge <int, double>(sourceNode, targetNode, 0.0); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <int, TaggedEdge <int, double> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <int, TaggedEdge <int, double> >(graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm); Assert.Throws <NegativeCapacityException>(() => algorithm.Compute(source, sink)); }
/// <summary> /// Computes the Edmonds-Karp maximums flow /// for a graph with positive capacities and /// flows. /// </summary> /// <typeparam name="TVertex">The type of the vertex.</typeparam> /// <typeparam name="TEdge">The type of the edge.</typeparam> /// <param name="visitedGraph">The visited graph.</param> /// <param name="edgeCapacities">The edge capacities.</param> /// <param name="source">The source.</param> /// <param name="sink">The sink.</param> /// <param name="flowPredecessors">The flow predecessors.</param> /// <param name="edgeFactory">the edge factory</param> /// <returns></returns> public static double MaximumFlowEdmondsKarp <TVertex, TEdge>( #if !NET20 this #endif IMutableVertexAndEdgeListGraph <TVertex, TEdge> visitedGraph, Func <TEdge, double> edgeCapacities, TVertex source, TVertex sink, out TryFunc <TVertex, TEdge> flowPredecessors, EdgeFactory <TVertex, TEdge> edgeFactory ) where TEdge : IEdge <TVertex> { Contract.Requires(visitedGraph != null); Contract.Requires(edgeCapacities != null); Contract.Requires(source != null); Contract.Requires(sink != null); Contract.Requires(!source.Equals(sink)); // compute maxflow var flow = new EdmondsKarpMaximumFlowAlgorithm <TVertex, TEdge>( visitedGraph, edgeCapacities, edgeFactory ); flow.Compute(source, sink); flowPredecessors = flow.Predecessors.TryGetValue; return(flow.MaxFlow); }
public EdmondsKarpMaximumFlowAlgorithm EdmundsKarp() { EdmondsKarpMaximumFlowAlgorithm maxFlow = new EdmondsKarpMaximumFlowAlgorithm( Graph, Capacities, ReversedEdges ); return maxFlow; }
private void InitializeGraph() { GenerateActivityGraph(); _flowAgorithm = new EdmondsKarpMaximumFlowAlgorithm <int, Edge <int> >( _graph, CalculateActivitySuccessorCapacity, CreateAdditionalEdgeFactory); }
public static string Test() { //////////////////////////////////////// // test maximum flow algorith ////////////////////////////////////////// var g = new BidirectionalGraph <string, Edge <string> >(true); string source = "A"; string sink = "G"; //Vertices ////////////// g.AddVertex("A"); g.AddVertex("B"); g.AddVertex("C"); g.AddVertex("D"); g.AddVertex("E"); g.AddVertex("F"); g.AddVertex("G"); //Edge //////////// var edgesList = new List <Edge <string> >(); var ad = new Edge <string>("A", "D"); g.AddEdge(ad); edgeCapacitiesDictionaryTest.Add(ad, 2); var ab = new Edge <string>("A", "B"); g.AddEdge(ab); edgeCapacitiesDictionaryTest.Add(ab, 3); var bc = new Edge <string>("B", "C"); g.AddEdge(bc); edgeCapacitiesDictionaryTest.Add(bc, 3); var ca = new Edge <string>("C", "A"); g.AddEdge(ca); edgeCapacitiesDictionaryTest.Add(ca, 4); var cd = new Edge <string>("C", "D"); g.AddEdge(cd); edgeCapacitiesDictionaryTest.Add(cd, 1); var de = new Edge <string>("D", "E"); g.AddEdge(de); edgeCapacitiesDictionaryTest.Add(de, 7); var df = new Edge <string>("D", "F"); g.AddEdge(df); edgeCapacitiesDictionaryTest.Add(df, 4); var eb = new Edge <string>("E", "B"); g.AddEdge(eb); edgeCapacitiesDictionaryTest.Add(eb, 1); var ce = new Edge <string>("C", "E"); g.AddEdge(ce); edgeCapacitiesDictionaryTest.Add(ce, 2); var eg = new Edge <string>("E", "G"); g.AddEdge(eg); edgeCapacitiesDictionaryTest.Add(eg, 3); var fg = new Edge <string>("F", "G"); g.AddEdge(fg); edgeCapacitiesDictionaryTest.Add(fg, 4); ///////////////////////////////////// // creating the augmentor //////////////////////////////////// var reversedEdgeAugmentor = new ReversedEdgeAugmentorAlgorithm <string, Edge <string> >(g, MyEdgeFactoryTest); reversedEdgeAugmentor.AddReversedEdges(); // (other option) new PushRelabelMaximumFlowAlgorithm MaximumFlowAlgorithm <string, Edge <string> > algo = new EdmondsKarpMaximumFlowAlgorithm <string, Edge <string> >(g, /*e => 2*/ ComputeCapacityTest, reversedEdgeAugmentor.ReversedEdges); algo.Compute(source, sink); //algo.Compute(); StringBuilder sb = new StringBuilder(); sb.AppendLine(string.Format("MaxFlow: {0}", algo.MaxFlow)); sb.AppendLine("Press <ENTER> to complete"); return(sb.ToString()); }
public static double Get(AdjacencyGraph <string, EquatableTaggedEdge <string, double> > graph, string source, string sink) { // edgeFactory will be used to create the reversed edges to store residual capacities using the ReversedEdgeAugmentorAlgorithm-class. // The edgeFactory assigns a capacity of 0.0 for the new edges because the initial (residual) capacity must be 0.0. EdgeFactory <string, EquatableTaggedEdge <string, double> > edgeFactory = (sourceNode, targetNode) => new EquatableTaggedEdge <string, double>(sourceNode, targetNode, 0.0); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <string, EquatableTaggedEdge <string, double> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <string, EquatableTaggedEdge <string, double> >(graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm); algorithm.Compute(source, sink); return(algorithm.MaxFlow); }
public void EdmondsKarpMaxFlow_WrongVertices_Throws() { var graph = new AdjacencyGraph <TestVertex, TaggedEdge <TestVertex, double> >(); EdgeFactory <TestVertex, TaggedEdge <TestVertex, double> > edgeFactory = (source, target) => new TaggedEdge <TestVertex, double>(source, target, 0.0); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <TestVertex, TaggedEdge <TestVertex, double> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <TestVertex, TaggedEdge <TestVertex, double> >(graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm); var vertex1 = new TestVertex("1"); var vertex2 = new TestVertex("2"); Assert.Throws <InvalidOperationException>(() => algorithm.Compute()); algorithm = new EdmondsKarpMaximumFlowAlgorithm <TestVertex, TaggedEdge <TestVertex, double> >( graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm) { Source = vertex1 }; Assert.Throws <InvalidOperationException>(() => algorithm.Compute()); algorithm = new EdmondsKarpMaximumFlowAlgorithm <TestVertex, TaggedEdge <TestVertex, double> >( graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm) { Source = vertex1, Sink = vertex2 }; Assert.Throws <VertexNotFoundException>(() => algorithm.Compute()); algorithm = new EdmondsKarpMaximumFlowAlgorithm <TestVertex, TaggedEdge <TestVertex, double> >( graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm) { Source = vertex1, Sink = vertex2 }; graph.AddVertex(vertex1); Assert.Throws <VertexNotFoundException>(() => algorithm.Compute()); }
public void NotReachableSink() { const string source = "A"; const string sink = "G"; var graph = new AdjacencyGraph <string, TaggedEdge <string, double> >(true); graph.AddVertexRange(new[] { "A", "B", "C", "D", "E", "F", "G" }); // TaggedEdge.Tag is the capacity of the edge graph.AddEdgeRange(new[] { new TaggedEdge <string, double>("A", "D", 3), new TaggedEdge <string, double>("A", "B", 3), new TaggedEdge <string, double>("B", "C", 4), new TaggedEdge <string, double>("C", "A", 3), new TaggedEdge <string, double>("C", "D", 1), new TaggedEdge <string, double>("D", "E", 2), new TaggedEdge <string, double>("D", "F", 6), new TaggedEdge <string, double>("E", "B", 1), new TaggedEdge <string, double>("C", "E", 2) }); // edgeFactory will be used to create the reversed edges to store residual capacities using the ReversedEdgeAugmentorAlgorithm-class. // The edgeFactory assigns a capacity of 0.0 for the new edges because the initial (residual) capacity must be 0.0. EdgeFactory <string, TaggedEdge <string, double> > edgeFactory = (sourceNode, targetNode) => new TaggedEdge <string, double>(sourceNode, targetNode, 0.0); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <string, TaggedEdge <string, double> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <string, TaggedEdge <string, double> >(graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm); algorithm.Compute(source, sink); Assert.AreEqual(source, algorithm.Source); Assert.AreEqual(sink, algorithm.Sink); Assert.AreEqual(graph.VertexCount, algorithm.VerticesColors.Count); foreach (KeyValuePair <string, GraphColor> pair in algorithm.VerticesColors) { Assert.AreEqual( pair.Key == sink ? GraphColor.White : GraphColor.Black, pair.Value); } Assert.AreEqual(0, algorithm.MaxFlow); }
public void EdmondsKarpMaxFlow_Throws() { var graph = new AdjacencyGraph <TestVertex, TaggedEdge <TestVertex, double> >(); EdgeFactory <TestVertex, TaggedEdge <TestVertex, double> > edgeFactory = (source, target) => new TaggedEdge <TestVertex, double>(source, target, 0.0); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <TestVertex, TaggedEdge <TestVertex, double> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <TestVertex, TaggedEdge <TestVertex, double> >(graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm); var vertex = new TestVertex("1"); // ReSharper disable AssignNullToNotNullAttribute Assert.Throws <ArgumentNullException>(() => algorithm.Compute(null, vertex)); Assert.Throws <ArgumentNullException>(() => algorithm.Compute(vertex, null)); Assert.Throws <ArgumentNullException>(() => algorithm.Compute(null, null)); // ReSharper restore AssignNullToNotNullAttribute }
public void GetVertexColor_Throws() { var graph = new AdjacencyGraph <int, Edge <int> >(); graph.AddVertexRange(new[] { 0, 1 }); Func <Edge <int>, double> capacities = edge => 1.0; EdgeFactory <int, Edge <int> > edgeFactory = (source, target) => new Edge <int>(source, target); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <int, Edge <int> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <int, Edge <int> >(graph, capacities, edgeFactory, reverseEdgesAlgorithm); algorithm.Compute(0, 1); // ReSharper disable once ReturnValueOfPureMethodIsNotUsed Assert.Throws <VertexNotFoundException>(() => algorithm.GetVertexColor(2)); }
public void GetVertexColor() { var graph = new AdjacencyGraph <int, Edge <int> >(); graph.AddVerticesAndEdge(new Edge <int>(1, 2)); graph.AddVertex(3); Func <Edge <int>, double> capacities = edge => 1.0; EdgeFactory <int, Edge <int> > edgeFactory = (source, target) => new Edge <int>(source, target); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <int, Edge <int> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <int, Edge <int> >(graph, capacities, edgeFactory, reverseEdgesAlgorithm); algorithm.Compute(1, 2); Assert.AreEqual(GraphColor.Black, algorithm.GetVertexColor(1)); Assert.AreEqual(GraphColor.White, algorithm.GetVertexColor(2)); Assert.AreEqual(GraphColor.White, algorithm.GetVertexColor(3)); }
public static string Main(BidirectionalGraph <Word, Edge <Word> > g) { gr = g; foreach (var item in g.Edges) { //edgeCapacitiesDictionary.Add(item, 0); } var reversedEdgeAugmentor = new ReversedEdgeAugmentorAlgorithm <Word, Edge <Word> >(g, MyEdgeFactory); reversedEdgeAugmentor.AddReversedEdges(); //p.; // (other option) new PushRelabelMaximumFlowAlgorithm MaximumFlowAlgorithm <Word, Edge <Word> > algo = new EdmondsKarpMaximumFlowAlgorithm <Word, Edge <Word> >(g, ComputeCapacity, reversedEdgeAugmentor.ReversedEdges); Dictionary <Edge <Word>, double> d = new Dictionary <Edge <Word>, double>(); foreach (var item in g.Edges) { algo = new EdmondsKarpMaximumFlowAlgorithm <Word, Edge <Word> >(g, ComputeCapacity, reversedEdgeAugmentor.ReversedEdges); double value = algo.Compute(item.Source, item.Target); d.Add(item, value); } //algo.Compute(); //algo.Compute(source, sink); //return algo.MaxFlow; StringBuilder sb = new StringBuilder(); foreach (var item in d) { sb.AppendLine(item.ToString()); } return(sb.ToString()); }
public static EdmondsKarpMaximumFlowAlgorithm <T, Edge <T> > CreateAlgorithmAndMaybeDoComputation <T>( [NotNull] ContractScenario <T> scenario) { var graph = new AdjacencyGraph <T, Edge <T> >(); graph.AddVerticesAndEdgeRange(scenario.EdgesInGraph.Select(e => new Edge <T>(e.Source, e.Target))); graph.AddVertexRange(scenario.SingleVerticesInGraph); double Capacities(Edge <T> edge) => 1.0; Edge <T> EdgeFactory(T source, T target) => new Edge <T>(source, target); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <T, Edge <T> >(graph, EdgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <T, Edge <T> >(graph, Capacities, EdgeFactory, reverseEdgesAlgorithm); if (scenario.DoComputation) { algorithm.Compute(scenario.Root, scenario.AccessibleVerticesFromRoot.First()); } return(algorithm); }
/// <inheritdoc /> protected override void InternalCompute() { ICancelManager cancelManager = Services.CancelManager; BipartiteToMaximumFlowGraphAugmentorAlgorithm <TVertex, TEdge> augmentor = null; ReversedEdgeAugmentorAlgorithm <TVertex, TEdge> reverser = null; try { if (cancelManager.IsCancelling) { return; } // Augmenting the graph augmentor = new BipartiteToMaximumFlowGraphAugmentorAlgorithm <TVertex, TEdge>( this, VisitedGraph, SourceToVertices, VerticesToSink, VertexFactory, EdgeFactory); augmentor.Compute(); if (cancelManager.IsCancelling) { return; } // Adding reverse edges reverser = new ReversedEdgeAugmentorAlgorithm <TVertex, TEdge>( VisitedGraph, EdgeFactory); reverser.AddReversedEdges(); if (cancelManager.IsCancelling) { return; } // Compute maximum flow var flow = new EdmondsKarpMaximumFlowAlgorithm <TVertex, TEdge>( this, VisitedGraph, edge => 1.0, EdgeFactory, reverser); flow.Compute(augmentor.SuperSource, augmentor.SuperSink); if (cancelManager.IsCancelling) { return; } foreach (TEdge edge in VisitedGraph.Edges) { if (Math.Abs(flow.ResidualCapacities[edge]) < float.Epsilon) { if (edge.Source.Equals(augmentor.SuperSource) || edge.Source.Equals(augmentor.SuperSink) || edge.Target.Equals(augmentor.SuperSource) || edge.Target.Equals(augmentor.SuperSink)) { // Skip all edges that connect to SuperSource or SuperSink continue; } _matchedEdges.Add(edge); } } } finally { if (reverser != null && reverser.Augmented) { reverser.RemoveReversedEdges(); } if (augmentor != null && augmentor.Augmented) { augmentor.Rollback(); } } }
protected override void InternalCompute() { var cancelManager = this.Services.CancelManager; this.MatchedEdges.Clear(); BipartiteToMaximumFlowGraphAugmentorAlgorithm <TVertex, TEdge> augmentor = null; ReversedEdgeAugmentorAlgorithm <TVertex, TEdge> reverser = null; try { if (cancelManager.IsCancelling) { return; } //augmenting graph augmentor = new BipartiteToMaximumFlowGraphAugmentorAlgorithm <TVertex, TEdge>( this, this.VisitedGraph, this.VertexSetA, this.VertexSetB, this.VertexFactory, this.EdgeFactory); augmentor.Compute(); if (cancelManager.IsCancelling) { return; } //adding reverse edges reverser = new ReversedEdgeAugmentorAlgorithm <TVertex, TEdge>( this, this.VisitedGraph, this.EdgeFactory ); reverser.AddReversedEdges(); if (cancelManager.IsCancelling) { return; } // compute maxflow var flow = new EdmondsKarpMaximumFlowAlgorithm <TVertex, TEdge>( this, this.VisitedGraph, e => 1, this.EdgeFactory ); flow.Compute(augmentor.SuperSource, augmentor.SuperSink); if (cancelManager.IsCancelling) { return; } foreach (var edge in this.VisitedGraph.Edges) { if (flow.ResidualCapacities[edge] == 0) { if (edge.Source.Equals(augmentor.SuperSource) || edge.Source.Equals(augmentor.SuperSource) || edge.Target.Equals(augmentor.SuperSink) || edge.Target.Equals(augmentor.SuperSink)) { //Skip all edges that connect to SuperSource or SuperSink continue; } this.MatchedEdges.Add(edge); } } } finally { if (reverser != null && reverser.Augmented) { reverser.RemoveReversedEdges(); reverser = null; } if (augmentor != null && augmentor.Augmented) { augmentor.Rollback(); augmentor = null; } } }
public void Constructor() { var graph = new AdjacencyGraph <int, Edge <int> >(); Func <Edge <int>, double> capacities = edge => 1.0; EdgeFactory <int, Edge <int> > edgeFactory = (source, target) => new Edge <int>(source, target); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <int, Edge <int> >(graph, edgeFactory); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <int, Edge <int> >( graph, capacities, edgeFactory, reverseEdgesAlgorithm); AssertAlgorithmProperties( algorithm, graph, capacities, edgeFactory); algorithm = new EdmondsKarpMaximumFlowAlgorithm <int, Edge <int> >( null, graph, capacities, edgeFactory, reverseEdgesAlgorithm); AssertAlgorithmProperties( algorithm, graph, capacities, edgeFactory); #region Local function void AssertAlgorithmProperties <TVertex, TEdge>( EdmondsKarpMaximumFlowAlgorithm <TVertex, TEdge> algo, IMutableVertexAndEdgeListGraph <TVertex, TEdge> g, Func <TEdge, double> c, EdgeFactory <int, Edge <int> > eFactory) where TEdge : IEdge <TVertex> { AssertAlgorithmState(algo, g); CollectionAssert.IsEmpty(algo.Predecessors); Assert.AreSame(c, algo.Capacities); CollectionAssert.IsEmpty(algo.ResidualCapacities); if (eFactory is null) { Assert.IsNotNull(algo.EdgeFactory); } else { Assert.AreSame(eFactory, algo.EdgeFactory); } CollectionAssert.IsEmpty(algo.ReversedEdges); Assert.AreEqual(default(TVertex), algo.Source); Assert.AreEqual(default(TVertex), algo.Sink); Assert.AreEqual(0.0, algo.MaxFlow); CollectionAssert.IsEmpty(algo.VerticesColors); } #endregion }
protected override void InternalCompute() { this.matchedEdges.Clear(); AllVerticesGraphAugmentorAlgorithm <TVertex, TEdge> augmentor = null; ReversedEdgeAugmentorAlgorithm <TVertex, TEdge> reverser = null; try { if (this.IsAborting) { return; } //augmenting graph augmentor = new AllVerticesGraphAugmentorAlgorithm <TVertex, TEdge>( this.VisitedGraph, this.VertexFactory, this.EdgeFactory); augmentor.Compute(); if (this.IsAborting) { return; } // adding reverse edges reverser = new ReversedEdgeAugmentorAlgorithm <TVertex, TEdge>( this.VisitedGraph, this.EdgeFactory ); reverser.AddReversedEdges(); if (this.IsAborting) { return; } // compute maxflow EdmondsKarpMaximumFlowAlgorithm <TVertex, TEdge> flow = new EdmondsKarpMaximumFlowAlgorithm <TVertex, TEdge>( this.VisitedGraph, AlgoUtility.ConstantCapacities(this.VisitedGraph, 1), reverser.ReversedEdges ); flow.Compute(augmentor.SuperSource, augmentor.SuperSink); if (this.IsAborting) { return; } foreach (TEdge edge in this.VisitedGraph.Edges) { if (this.IsAborting) { return; } if (flow.ResidualCapacities[edge] == 0) { this.matchedEdges.Add(edge); } } } finally { if (reverser != null && reverser.Augmented) { reverser.RemoveReversedEdges(); reverser = null; } if (augmentor != null && augmentor.Augmented) { augmentor.Rollback(); augmentor = null; } } }
public void SimpleFlow() { const string source = "A"; const string sink = "G"; var graph = new AdjacencyGraph <string, EquatableTaggedEdge <string, double> >(true); graph.AddVertexRange(new[] { "A", "B", "C", "D", "E", "F", "G" }); // TaggedEdge.Tag is the capacity of the edge graph.AddEdgeRange(new[] { new EquatableTaggedEdge <string, double>("A", "D", 3), new EquatableTaggedEdge <string, double>("A", "B", 3), new EquatableTaggedEdge <string, double>("B", "C", 4), new EquatableTaggedEdge <string, double>("C", "A", 3), new EquatableTaggedEdge <string, double>("C", "D", 1), new EquatableTaggedEdge <string, double>("D", "E", 2), new EquatableTaggedEdge <string, double>("D", "F", 6), new EquatableTaggedEdge <string, double>("E", "B", 1), new EquatableTaggedEdge <string, double>("C", "E", 2), new EquatableTaggedEdge <string, double>("E", "G", 1), new EquatableTaggedEdge <string, double>("F", "G", 9) }); // edgeFactory will be used to create the reversed edges to store residual capacities using the ReversedEdgeAugmentorAlgorithm-class. // The edgeFactory assigns a capacity of 0.0 for the new edges because the initial (residual) capacity must be 0.0. EdgeFactory <string, EquatableTaggedEdge <string, double> > edgeFactory = (sourceNode, targetNode) => new EquatableTaggedEdge <string, double>(sourceNode, targetNode, 0.0); var reverseEdgesAlgorithm = new ReversedEdgeAugmentorAlgorithm <string, EquatableTaggedEdge <string, double> >(graph, edgeFactory); reverseEdgesAlgorithm.AddReversedEdges(); var algorithm = new EdmondsKarpMaximumFlowAlgorithm <string, EquatableTaggedEdge <string, double> >(graph, edge => edge.Tag, edgeFactory, reverseEdgesAlgorithm); algorithm.Compute(source, sink); Assert.AreEqual(source, algorithm.Source); Assert.AreEqual(sink, algorithm.Sink); Assert.AreEqual(5, algorithm.MaxFlow); CheckReversedEdges(); CheckPredecessors(); CheckResidualCapacities(); #region Local function void CheckReversedEdges() { Assert.IsTrue(algorithm.ReversedEdges.Count % 2 == 0); foreach (var pair in algorithm.ReversedEdges) { Assert.AreEqual(pair.Key.Source, pair.Value.Target); Assert.AreEqual(pair.Key.Target, pair.Value.Source); } } void CheckPredecessors() { Assert.AreEqual(graph.VertexCount - 1, algorithm.Predecessors.Count); CollectionAssert.AreEquivalent( new Dictionary <string, EquatableTaggedEdge <string, double> > { ["B"] = new EquatableTaggedEdge <string, double>("A", "B", 3), ["C"] = new EquatableTaggedEdge <string, double>("B", "C", 4), ["D"] = new EquatableTaggedEdge <string, double>("E", "D", 0), ["E"] = new EquatableTaggedEdge <string, double>("C", "E", 2), ["F"] = new EquatableTaggedEdge <string, double>("D", "F", 6), ["G"] = new EquatableTaggedEdge <string, double>("F", "G", 9), }, algorithm.Predecessors); } void CheckResidualCapacities() { Assert.AreEqual(graph.EdgeCount, algorithm.ResidualCapacities.Count); CollectionAssert.AreEquivalent( new Dictionary <EquatableTaggedEdge <string, double>, double> { [new EquatableTaggedEdge <string, double>("A", "B", 3)] = 1, [new EquatableTaggedEdge <string, double>("A", "C", 0)] = 0, [new EquatableTaggedEdge <string, double>("A", "D", 3)] = 0, [new EquatableTaggedEdge <string, double>("B", "A", 0)] = 2, [new EquatableTaggedEdge <string, double>("B", "C", 4)] = 2, [new EquatableTaggedEdge <string, double>("B", "E", 0)] = 0, [new EquatableTaggedEdge <string, double>("C", "A", 3)] = 3, [new EquatableTaggedEdge <string, double>("C", "B", 0)] = 2, [new EquatableTaggedEdge <string, double>("C", "D", 1)] = 0, [new EquatableTaggedEdge <string, double>("C", "E", 2)] = 1, [new EquatableTaggedEdge <string, double>("D", "A", 0)] = 3, [new EquatableTaggedEdge <string, double>("D", "C", 0)] = 1, [new EquatableTaggedEdge <string, double>("D", "E", 2)] = 2, [new EquatableTaggedEdge <string, double>("D", "F", 6)] = 2, [new EquatableTaggedEdge <string, double>("E", "B", 1)] = 1, [new EquatableTaggedEdge <string, double>("E", "C", 0)] = 1, [new EquatableTaggedEdge <string, double>("E", "D", 0)] = 0, [new EquatableTaggedEdge <string, double>("E", "G", 1)] = 0, [new EquatableTaggedEdge <string, double>("F", "D", 0)] = 4, [new EquatableTaggedEdge <string, double>("F", "G", 9)] = 5, [new EquatableTaggedEdge <string, double>("G", "E", 0)] = 1, [new EquatableTaggedEdge <string, double>("G", "F", 0)] = 4, }, algorithm.ResidualCapacities); } #endregion }