Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
FlowForge
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Timon Römer
FlowForge
Commits
68cca3f9
Commit
68cca3f9
authored
7 months ago
by
Römer
Browse files
Options
Downloads
Patches
Plain Diff
Fixes order for DFS
parent
e44a2f15
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
FlowGraph.cs
+24
-0
24 additions, 0 deletions
FlowGraph.cs
FordFulkersonAlgorithm.cs
+103
-66
103 additions, 66 deletions
FordFulkersonAlgorithm.cs
with
127 additions
and
66 deletions
FlowGraph.cs
+
24
−
0
View file @
68cca3f9
using
System.Collections.Generic
;
using
System.Linq
;
using
QuikGraph
;
namespace
FlowForge
;
...
...
@@ -42,6 +43,29 @@ public class FlowGraph
Graph
.
AddEdge
(
edge
);
}
public
void
ResetFlow
()
{
List
<
FlowEdge
>
allEdges
=
GetEdges
().
ToList
();
foreach
(
var
edge
in
allEdges
)
{
edge
.
CurrentFlow
=
0
;
}
}
public
void
RemoveAllBackwardsEdges
()
{
List
<
FlowEdge
>
allEdges
=
GetEdges
().
ToList
();
foreach
(
var
edge
in
allEdges
.
Where
(
edge
=>
edge
.
IsBackwards
))
{
Graph
.
RemoveEdge
(
edge
);
}
}
public
List
<
FlowEdge
>
GetAllEdgesWithFlow
()
{
return
GetEdges
().
Where
(
edge
=>
edge
.
CurrentFlow
>
0
).
ToList
();
}
public
IEnumerable
<
FlowEdge
>
GetEdges
()
{
return
Graph
.
Edges
;
...
...
This diff is collapsed.
Click to expand it.
FordFulkersonAlgorithm.cs
+
103
−
66
View file @
68cca3f9
...
...
@@ -33,47 +33,48 @@ public class FordFulkersonAlgorithm
FlowNode
?
target
=
_flowGraph
.
GetVertexById
(
TargetId
);
if
(
source
==
null
||
target
==
null
)
{
throw
new
ArgumentException
(
"Invalid source or target node!"
);
}
Console
.
WriteLine
(
"Start of Ford-Fulkerson Algorithm..."
);
double
maxFlow
=
0.0
;
var
pathFlow
=
new
Dictionary
<
FlowEdge
,
double
>();
var
allEdges
=
_flowGraph
.
GetEdges
();
foreach
(
var
edge
in
allEdges
)
{
edge
.
CurrentFlow
=
0
;
}
Console
.
WriteLine
(
"Start of Ford-Fulkerson Algorithm..."
);
_flowGraph
.
ResetFlow
();
_graphStates
.
Clear
();
SaveGraphState
();
// execute as long as there is an augmenting path
while
(
FindAugmentingPath
(
source
,
target
,
pathFlow
,
strategy
))
while
(
strategy
==
SearchStrategy
.
BreadthFirstSearch
?
FindAugmentingPath
Bfs
(
source
,
target
,
pathFlow
)
:
FindAugmentingPathDfs
(
source
,
target
,
pathFlow
))
{
PrintOrderedPath
(
pathFlow
);
// 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
}
"
);
double
pathMinFlow
=
FindBottleneckInPath
(
pathFlow
);
// add forward flow along the augmenting path
foreach
(
var
edge
in
pathFlow
.
Keys
)
{
//edge.Residual -= pathMinFlow;
edge
.
CurrentFlow
+=
pathMinFlow
;
Console
.
WriteLine
(
$"Updating forward edge
{
edge
.
Source
.
Id
}
->
{
edge
.
Target
.
Id
}
, New
Residual:
{
edge
.
Residual
}
"
);
Console
.
WriteLine
(
$"Updating forward edge
{
edge
.
Source
.
Id
}
->
{
edge
.
Target
.
Id
}
, New
Flow:
{
edge
.
CurrentFlow
}
"
);
}
// Convert pathFlow to a list of edges for highlighting
var
augmentingPath
=
pathFlow
.
Keys
.
ToList
();
SaveGraphState
(
augmentingPath
);
SaveGraphState
(
pathFlow
.
Keys
.
ToList
());
// change residual where necessary
foreach
(
var
edge
in
pathFlow
.
Keys
.
Where
(
edge
=>
edge
.
IsBackwards
))
{
if
(!
_flowGraph
.
Graph
.
TryGetEdge
(
edge
.
Target
,
edge
.
Source
,
out
var
forwardEdge
))
continue
;
forwardEdge
.
CurrentFlow
-=
edge
.
CurrentFlow
;
edge
.
CurrentFlow
=
0
;
if
(
forwardEdge
.
CurrentFlow
!=
0
)
continue
;
_flowGraph
.
Graph
.
RemoveEdge
(
edge
);
pathFlow
.
Remove
(
edge
);
}
List
<
FlowEdge
>
residualChanges
=
new
List
<
FlowEdge
>();
...
...
@@ -110,56 +111,46 @@ public class FordFulkersonAlgorithm
SaveGraphState
(
residualChanges
);
}
Console
.
WriteLine
(
"No Augmenting Path found anymore!\n"
);
Console
.
WriteLine
(
$
"No Augmenting Path found anymore!\n
Max flow found:
{
maxFlow
}
\n
"
);
Console
.
WriteLine
(
$"Max flow found:
{
maxFlow
}
\n"
);
List
<
FlowEdge
>
edgesWithFlow
=
allEdges
.
Where
(
edge
=>
edge
.
CurrentFlow
>
0
).
ToList
();
SaveGraphState
(
edgesWithFlow
);
_flowGraph
.
RemoveAllBackwardsEdges
();
SaveGraphState
(
_flowGraph
.
GetAllEdgesWithFlow
());
// return maximum flow after no augmenting paths were found anymore
return
maxFlow
;
}
private
bool
FindAugmentingPath
(
FlowNode
source
,
FlowNode
target
,
Dictionary
<
FlowEdge
,
double
>
pathFlow
,
SearchStrategy
strategy
)
private
static
double
FindBottleneckInPath
(
Dictionary
<
FlowEdge
,
double
>
pathFlow
)
{
// parent map to walk back path
var
parentMap
=
new
Dictionary
<
FlowNode
,
FlowEdge
>();
// Choose the appropriate data structure based on the strategy
IEnumerable
<
FlowNode
>
nodesToVisit
;
if
(
strategy
==
SearchStrategy
.
BreadthFirstSearch
)
// calculate bottleneck in augmenting path
double
pathMinFlow
=
double
.
MaxValue
;
foreach
(
var
edge
in
pathFlow
.
Keys
)
{
var
queue
=
new
Queue
<
FlowNode
>();
queue
.
Enqueue
(
source
);
nodesToVisit
=
queue
;
pathMinFlow
=
Math
.
Min
(
pathMinFlow
,
pathFlow
[
edge
]);
}
else
{
var
stack
=
new
Stack
<
FlowNode
>();
stack
.
Push
(
source
);
nodesToVisit
=
stack
;
Console
.
WriteLine
(
$"Bottleneck (minimum flow in path):
{
pathMinFlow
}
"
);
return
pathMinFlow
;
}
private
bool
FindAugmentingPathBfs
(
FlowNode
source
,
FlowNode
target
,
Dictionary
<
FlowEdge
,
double
>
pathFlow
)
{
// parent map to walk back path
var
parentMap
=
new
Dictionary
<
FlowNode
,
FlowEdge
>();
Queue
<
FlowNode
>
nodesToVisit
=
new
Queue
<
FlowNode
>();
nodesToVisit
.
Enqueue
(
source
);
// map to store visited nodes
var
visited
=
new
HashSet
<
FlowNode
>
{
source
};
while
(
nodesToVisit
.
Any
())
{
var
current
=
strategy
==
SearchStrategy
.
BreadthFirstSearch
?
((
Queue
<
FlowNode
>)
nodesToVisit
)
.
Dequeue
()
:
((
Stack
<
FlowNode
>)
nodesToVisit
).
Pop
()
;
var
current
=
nodesToVisit
.
Dequeue
();
Console
.
WriteLine
(
"Current Node: "
+
current
);
var
outEdges
=
_flowGraph
.
Graph
.
OutEdges
(
current
).
ToList
();
List
<
FlowEdge
>
sortedOutEdges
;
if
(
strategy
==
SearchStrategy
.
BreadthFirstSearch
)
{
sortedOutEdges
=
outEdges
.
OrderBy
(
edge
=>
int
.
Parse
(
edge
.
Target
.
Id
)).
ToList
();
}
else
{
sortedOutEdges
=
outEdges
.
OrderBy
(
edge
=>
int
.
Parse
(
edge
.
Target
.
Id
)).
ToList
();
}
List
<
FlowEdge
>
sortedOutEdges
=
outEdges
.
OrderBy
(
edge
=>
int
.
Parse
(
edge
.
Target
.
Id
)).
ToList
();
Console
.
WriteLine
(
"Sorted out edges for node:"
);
foreach
(
FlowEdge
edge
in
sortedOutEdges
)
...
...
@@ -192,25 +183,71 @@ public class FordFulkersonAlgorithm
nodesToAdd
.
Add
(
currentEdge
.
Target
);
}
if
(
strategy
==
SearchStrategy
.
BreadthFirstSearch
)
{
foreach
(
var
node
in
nodesToAdd
.
OrderBy
(
n
=>
int
.
Parse
(
n
.
Id
)))
{
((
Queue
<
FlowNode
>)
nodesToVisit
).
Enqueue
(
node
);
nodesToVisit
.
Enqueue
(
node
);
}
}
return
false
;
}
else
private
bool
FindAugmentingPathDfs
(
FlowNode
source
,
FlowNode
target
,
Dictionary
<
FlowEdge
,
double
>
pathFlow
)
{
foreach
(
var
node
in
nodesToAdd
.
OrderByDescending
(
n
=>
int
.
Parse
(
n
.
Id
)))
// parent map to walk back path
var
parentMap
=
new
Dictionary
<
FlowNode
,
FlowEdge
>();
Stack
<
FlowNode
>
nodesToVisit
=
new
Stack
<
FlowNode
>();
nodesToVisit
.
Push
(
source
);
// map to store visited nodes
var
visited
=
new
HashSet
<
FlowNode
>();
while
(
nodesToVisit
.
Any
())
{
((
Stack
<
FlowNode
>)
nodesToVisit
).
Push
(
node
);
var
current
=
nodesToVisit
.
Pop
();
Console
.
WriteLine
(
"Current Node: "
+
current
);
// if we reached the target node
if
(
current
.
Equals
(
target
))
{
BuildAugmentingPath
(
source
,
target
,
parentMap
,
pathFlow
);
return
true
;
}
var
outEdges
=
_flowGraph
.
Graph
.
OutEdges
(
current
).
ToList
();
List
<
FlowEdge
>
sortedOutEdges
=
outEdges
.
OrderBy
(
edge
=>
int
.
Parse
(
edge
.
Target
.
Id
)).
ToList
();
Console
.
WriteLine
(
"Sorted out edges for node:"
);
foreach
(
FlowEdge
edge
in
sortedOutEdges
)
{
Console
.
WriteLine
(
$"
{
edge
.
Source
.
Id
}
->
{
edge
.
Target
.
Id
}
, Current Flow:
{
edge
.
CurrentFlow
}
"
);
}
Console
.
WriteLine
(
"Looping through:"
);
List
<
FlowNode
>
nodesToAdd
=
new
List
<
FlowNode
>();
// go through all outgoing edges
foreach
(
FlowEdge
currentEdge
in
sortedOutEdges
)
{
if
(
currentEdge
.
Residual
<=
0
||
visited
.
Contains
(
currentEdge
.
Target
))
continue
;
Console
.
WriteLine
(
$"
{
currentEdge
.
Source
.
Id
}
->
{
currentEdge
.
Target
.
Id
}
, Current Flow:
{
currentEdge
.
CurrentFlow
}
"
);
parentMap
[
currentEdge
.
Target
]
=
currentEdge
;
nodesToAdd
.
Add
(
currentEdge
.
Target
);
}
return
false
;
foreach
(
var
node
in
nodesToAdd
.
OrderByDescending
(
n
=>
int
.
Parse
(
n
.
Id
)))
{
nodesToVisit
.
Push
(
node
);
}
visited
.
Add
(
current
);
}
return
false
;
}
private
static
void
BuildAugmentingPath
(
FlowNode
source
,
FlowNode
target
,
Dictionary
<
FlowNode
,
FlowEdge
>
parentMap
,
Dictionary
<
FlowEdge
,
double
>
pathFlow
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment