diff --git a/.idea/.idea.FlowForge/.idea/.name b/.idea/.idea.FlowForge/.idea/.name new file mode 100644 index 0000000000000000000000000000000000000000..2453a22f2c20df743c6dc8e165e025babaee891f --- /dev/null +++ b/.idea/.idea.FlowForge/.idea/.name @@ -0,0 +1 @@ +FlowForge \ No newline at end of file diff --git a/FlowEdge.cs b/FlowEdge.cs index c37eaf561425a1647643de09b1b375727b715c06..f16855d837bc7c2791552b609992db58bfb5c40b 100644 --- a/FlowEdge.cs +++ b/FlowEdge.cs @@ -13,7 +13,7 @@ public class FlowEdge : Edge<FlowNode> { IsBackwards = false; MaxFlow = maxFlow; - Residual = 0; + Residual = maxFlow; } public override string ToString() diff --git a/FlowForge.csproj b/FlowForge.csproj index 777f105ac0886046e1cd0abee4b5f8fd335bb2be..ea5dbc587d632f353639a8ec6f64e50ccad27804 100644 --- a/FlowForge.csproj +++ b/FlowForge.csproj @@ -5,6 +5,7 @@ <TargetFramework>net6.0-windows</TargetFramework> <Nullable>enable</Nullable> <UseWPF>true</UseWPF> + <ApplicationIcon>./icons/logo.ico</ApplicationIcon> </PropertyGroup> <ItemGroup> diff --git a/FlowForge.sln.DotSettings.user b/FlowForge.sln.DotSettings.user new file mode 100644 index 0000000000000000000000000000000000000000..a7132a1f49d791829c15f644cbd531f3e9b159d7 --- /dev/null +++ b/FlowForge.sln.DotSettings.user @@ -0,0 +1,3 @@ +<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> + <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABidirectionalGraph_002Ecs_002Fl_003AC_0021_003FUsers_003Fmp455017_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fa8e81c4118651b5932b855cf99986877c2c24685d864158c9053e4f62e213fce_003FBidirectionalGraph_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> + <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIDictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fmp455017_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb756d57b94fb4ab9aa95a9b2a97fce1fa24ea0_003Fa1_003F8276683c_003FIDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary> \ No newline at end of file diff --git a/FordFulkersonAlgorithm.cs b/FordFulkersonAlgorithm.cs index 9a3a6a82ed3a00e2e49aa06d8c2a9b9cec636cb5..ac1e578f1e372ceecfe82185f0775272aa045f04 100644 --- a/FordFulkersonAlgorithm.cs +++ b/FordFulkersonAlgorithm.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace FlowForge; @@ -30,21 +31,32 @@ public class FordFulkersonAlgorithm { edge.Residual = edge.MaxFlow; } + + Console.WriteLine("Start of Ford-Fulkerson Algorithm..."); // execute as long as there is an augmenting path - while (FindAugmentingPath(source, target, pathFlow)) + while (FindAugmentingPathBfs(source, target, pathFlow)) { + Console.WriteLine("Augmenting Path found:"); + foreach (var edge in pathFlow.Keys) + { + Console.WriteLine($"{edge.Source.Id} -> {edge.Target.Id}, Residual Capacity: {pathFlow[edge]}"); + } + // calculate bottleneck in augmenting path double pathMinFlow = double.MaxValue; foreach (var edge in pathFlow.Keys) { pathMinFlow = Math.Min(pathMinFlow, pathFlow[edge]); } + Console.WriteLine($"Bottleneck (minimum flow in path): {pathMinFlow}"); // add flow along the augmenting path foreach (var edge in pathFlow.Keys) { edge.Residual -= pathMinFlow; + Console.WriteLine($"Updating forward edge {edge.Source.Id} -> {edge.Target.Id}, New Residual: {edge.Residual}"); + // check if backwards edge exists FlowEdge? reverseEdge; @@ -57,21 +69,32 @@ public class FordFulkersonAlgorithm reverseEdge.IsBackwards = true; _flowGraph.Graph.AddEdge(reverseEdge); + + Console.WriteLine($"Creating reverse edge {reverseEdge.Source.Id} -> {reverseEdge.Target.Id}"); + } + + if (reverseEdge != null) + { + reverseEdge.Residual += pathMinFlow; + + Console.WriteLine($"Updating reverse edge {reverseEdge.Source.Id} -> {reverseEdge.Target.Id}, New Residual: {reverseEdge.Residual}"); } - - if (reverseEdge != null) reverseEdge.Residual += pathMinFlow; } // add to total flow maxFlow += pathMinFlow; + Console.WriteLine($"Current max flow: {maxFlow}\n"); } + Console.WriteLine("No Augmenting Path found anymore!\n"); + + Console.WriteLine($"Max flow found: {maxFlow}\n"); // return maximum flow after no augmenting paths were found anymore return maxFlow; } - public bool FindAugmentingPath(FlowNode source, FlowNode target, Dictionary<FlowEdge, double> pathFlow) + public bool FindAugmentingPathBfs(FlowNode source, FlowNode target, Dictionary<FlowEdge, double> pathFlow) { // parent map to walk back path var parentMap = new Dictionary<FlowNode, FlowEdge>(); @@ -87,10 +110,12 @@ public class FordFulkersonAlgorithm { FlowNode current = queue.Dequeue(); - var outEdges = _flowGraph.Graph.OutEdges(current); + var outEdges = _flowGraph.Graph.OutEdges(current).ToList(); + + var sortedOutEdges = outEdges.OrderBy(edge => edge.Target.Id); // go through all outgoing edges - foreach (FlowEdge currentEdge in outEdges) + foreach (FlowEdge currentEdge in sortedOutEdges) { if (currentEdge.Residual <= 0 || visited.Contains(currentEdge.Target)) continue; @@ -121,5 +146,58 @@ public class FordFulkersonAlgorithm return false; } + + public bool FindAugmentingPathDfs(FlowNode source, FlowNode target, Dictionary<FlowEdge, double> pathFlow) + { + // parent map to walk back path + var parentMap = new Dictionary<FlowNode, FlowEdge>(); + + // queue for breath first search + var stack = new Stack<FlowNode>(); + stack.Push(source); + + // map to store visited nodes + var visited = new HashSet<FlowNode> { source }; + + while (stack.Count > 0) + { + FlowNode current = stack.Pop(); + + var outEdges = _flowGraph.Graph.OutEdges(current).ToList(); + + var sortedOutEdges = outEdges.OrderBy(edge => edge.Target.Id); + + // go through all outgoing edges + foreach (FlowEdge currentEdge in sortedOutEdges) + { + if (currentEdge.Residual <= 0 || visited.Contains(currentEdge.Target)) continue; + + visited.Add(currentEdge.Target); + parentMap.Add(currentEdge.Target, currentEdge); + + // if we reached the target node + if (currentEdge.Target.Equals(target)) + { + FlowNode currentNode = target; + pathFlow.Clear(); + + while (currentNode != source) + { + FlowEdge pathEdge = parentMap[currentNode]; + pathFlow.Add(pathEdge, pathEdge.Residual); + currentNode = pathEdge.Source; + } + + // return the augmenting path found + return true; + } + + // search further + stack.Push(currentEdge.Target); + } + } + + return false; + } } diff --git a/MainWindow.xaml b/MainWindow.xaml index fd8a744d84473c4205352400c86e3d4494a9a93c..cdaf38b5dc4cdfedc00c99ffb5319e64772c412e 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -1,7 +1,7 @@ <Window x:Class="FlowForge.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - Title="FlowForge" Height="600" Width="800"> + Title="Flow-Forge" Height="600" Width="800"> <Grid x:Name="MainGrid"> <!-- Define two rows: one fixed height for the button and one for the graph viewer --> <Grid.RowDefinitions> @@ -22,12 +22,23 @@ Click="InitializeGraphButton_Click"/> <!-- Second Button in the first row --> - <Button x:Name="RunAlgorithmButton" + <Button x:Name="RunFordFulkersonButton" Content="Run Ford-Fulkerson" Width="150" Height="40" VerticalAlignment="Center" HorizontalAlignment="Left" + Margin="350,10,0,10" + Grid.Row="0" + Click="RunAlgorithmButton_Click"/> + + <!-- Second Button in the first row --> + <Button x:Name="RunEdmondsKarpButton" + Content="Run Edmonds–Karp" + Width="150" + Height="40" + VerticalAlignment="Center" + HorizontalAlignment="Left" Margin="180,10,0,10" Grid.Row="0" Click="RunAlgorithmButton_Click"/> diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index dad6b5126b466e06f71cde9876bc17c2fb35ecff..5f822db480913e60c8d4b74ce820eabd877d6249 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -129,7 +129,6 @@ namespace FlowForge double maxFlow = _fordFulkerson.Run("1", "4"); - Console.WriteLine($"Maximaler Fluss von Quelle zu Senke: {maxFlow}"); MessageBox.Show($"Maximaler Fluss von Quelle zu Senke: {maxFlow}"); diff --git a/icons/logo.ico b/icons/logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..9a1781c3af8b5eb8f973e7904879446ecaa5830c Binary files /dev/null and b/icons/logo.ico differ diff --git a/icons/logo.png b/icons/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..45d572c99ade6790e57e2b9bff3f19684de2cc6e Binary files /dev/null and b/icons/logo.png differ