Skip to content

Commit b4a2a15

Browse files
authored
Merge pull request #63 from Debashis08/feature-graph-implementation
Feature graph implementation
2 parents 78ad19c + 225d1ca commit b4a2a15

File tree

7 files changed

+238
-2
lines changed

7 files changed

+238
-2
lines changed

Headers/0003_Graph/0018_MaximumFlowGoldbergGenericPushRelabel.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#pragma once
22

3-
#include<map>
43
#include<vector>
54
#include<queue>
65
using namespace std;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include<vector>
4+
#include<list>
5+
using namespace std;
6+
7+
namespace MaximumFlowRelabelToFront
8+
{
9+
class Graph
10+
{
11+
private:
12+
int _noOfVertices;
13+
int _source;
14+
int _sink;
15+
int _maximumFlow;
16+
vector<vector<int>> _adjMatrix;
17+
vector<vector<int>> _residualGraph;
18+
vector<int> _excessFlow;
19+
vector<int> _height;
20+
vector<bool> _visited;
21+
list<int> _nodeList;
22+
void InitializePreflow();
23+
void Discharge(int nodeU);
24+
void Push(int nodeU, int nodeV);
25+
void Relabel(int nodeU);
26+
public:
27+
void CreateGraph(int noOfVertices);
28+
void PushDirectedEdge(int valueU, int valueV, int capacity);
29+
int FindMaximumFlowRelabelToFront();
30+
};
31+
}

SourceCodes/0003_Graph/0018_MaximumFlowGoldbergGenericPushRelabel.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "../Headers/0003_Graph/0018_MaximumFlowGoldbergGenericPushRelabel.h"
2-
#include<queue>
32
#include<climits>
43
using namespace std;
54

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#include "../Headers/0003_Graph/0019_MaximumFlowRelabelToFront.h"
2+
#include<climits>
3+
#include<iterator>
4+
using namespace std;
5+
6+
namespace MaximumFlowRelabelToFront
7+
{
8+
// Graph Private Member Methods
9+
10+
// Initializes Pre-Flow in the given Flow Network
11+
void Graph::InitializePreflow()
12+
{
13+
// The height of source is set to highest possible height value
14+
this->_height[this->_source] = this->_noOfVertices;
15+
16+
// Iterating over all the vertices
17+
for (int i = 0; i < this->_noOfVertices; i++)
18+
{
19+
// For the all the edges (source, v)
20+
if (this->_residualGraph[this->_source][i] > 0)
21+
{
22+
// v.excessFlow = capacity(source, v)
23+
this->_excessFlow[i] = this->_residualGraph[this->_source][i];
24+
25+
// source.excessFlow = source.excessFlow - capacity(source, v)
26+
this->_excessFlow[this->_source] = this->_excessFlow[this->_source] - this->_residualGraph[this->_source][i];
27+
28+
// Adjusting the flow and reverse flow along source->v and v->source respectively
29+
this->_residualGraph[i][this->_source] = this->_residualGraph[this->_source][i];
30+
this->_residualGraph[this->_source][i] = 0;
31+
}
32+
}
33+
}
34+
35+
// Discharges the excess flow from nodeU
36+
void Graph::Discharge(int nodeU)
37+
{
38+
// Check if excess flow of nodeU is > 0
39+
while (this->_excessFlow[nodeU] > 0)
40+
{
41+
// Falg to check if any amount of excess flow is pushed to any neighbour vertex
42+
bool hasPushed = false;
43+
44+
// Iterating over all of the vertices
45+
for (int nodeV = 0; nodeV < this->_noOfVertices; nodeV++)
46+
{
47+
// For G'.Adj[nodeU] check if edge (nodeU, nodeV) is admissible
48+
if (this->_residualGraph[nodeU][nodeV] > 0 && this->_height[nodeU] == 1 + this->_height[nodeV])
49+
{
50+
// Push excess flow along the admissible edge (nodeU, nodeV)
51+
this->Push(nodeU, nodeV);
52+
// Set the hasPushed flag to true
53+
hasPushed = true;
54+
// Check if there is no excess flow left in nodeU then no need to check any more admissible edge going from nodeU
55+
if (this->_excessFlow[nodeU] == 0)
56+
{
57+
// Then break from iterating over G'.Adj[nodeU]
58+
break;
59+
}
60+
}
61+
}
62+
63+
// Check if Push operation is not done yet
64+
if (!hasPushed)
65+
{
66+
// Then it indicates that all the outgoing edges from nodeU are inadmissible
67+
// so perform the Relabel operation on nodeU
68+
this->Relabel(nodeU);
69+
}
70+
}
71+
}
72+
73+
// Pushes the flow from nodeU to its neighbour vertices
74+
void Graph::Push(int nodeU, int nodeV)
75+
{
76+
// Calculate the flow amount to be added along the edge and excess flow subtracted from nodeU
77+
int minimumFlow = min(this->_residualGraph[nodeU][nodeV], this->_excessFlow[nodeU]);
78+
79+
// Adjust the flow and the reverse flow along (nodeU, nodeV)
80+
this->_residualGraph[nodeU][nodeV] = this->_residualGraph[nodeU][nodeV] - minimumFlow;
81+
this->_residualGraph[nodeV][nodeU] = this->_residualGraph[nodeV][nodeU] + minimumFlow;
82+
83+
// Adjust the excess flows in nodeU and nodeV
84+
this->_excessFlow[nodeU] = this->_excessFlow[nodeU] - minimumFlow;
85+
this->_excessFlow[nodeV] = this->_excessFlow[nodeV] + minimumFlow;
86+
}
87+
88+
// Relabels height of vertex nodeU when there are outgoing non-saturated edges available
89+
void Graph::Relabel(int nodeU)
90+
{
91+
int minimumHeight = INT_MAX;
92+
93+
// Iterating over all the vertices
94+
for (int nodeV = 0; nodeV < this->_noOfVertices; nodeV++)
95+
{
96+
// For G'.Adj[nodeU] select for which nodeV, height[nodeU] <= height[nodeV]
97+
if (this->_residualGraph[nodeU][nodeV] > 0 && this->_height[nodeU] <= this->_height[nodeV])
98+
{
99+
// Get the minimum height among all these G'.Adj[nodeU]
100+
minimumHeight = min(minimumHeight, this->_height[nodeV]);
101+
}
102+
}
103+
104+
// Set height[nodeU]
105+
this->_height[nodeU] = minimumHeight + 1;
106+
}
107+
108+
109+
// Graph Public Member Methods
110+
void Graph::CreateGraph(int noOfVertices)
111+
{
112+
this->_noOfVertices = noOfVertices;
113+
this->_source = 0;
114+
this->_sink = this->_noOfVertices - 1;
115+
this->_maximumFlow = 0;
116+
this->_adjMatrix = vector<vector<int>>(this->_noOfVertices, vector<int>(this->_noOfVertices, 0));
117+
this->_excessFlow = vector<int>(this->_noOfVertices, 0);
118+
this->_height = vector<int>(this->_noOfVertices, 0);
119+
this->_visited = vector<bool>(this->_noOfVertices, false);
120+
}
121+
122+
void Graph::PushDirectedEdge(int valueU, int valueV, int capacity)
123+
{
124+
this->_adjMatrix[valueU][valueV] = capacity;
125+
}
126+
127+
int Graph::FindMaximumFlowRelabelToFront()
128+
{
129+
this->_residualGraph = this->_adjMatrix;
130+
131+
// Initialize Pre-flow
132+
this->InitializePreflow();
133+
134+
// Make the list L = G.V - {source, sink}
135+
for (int i = 0; i < this->_noOfVertices; i++)
136+
{
137+
if (i != this->_source && i != this->_sink)
138+
{
139+
this->_nodeList.push_back(i);
140+
}
141+
}
142+
143+
// Set current vertex = L.head
144+
list<int>::iterator nodeUiterator = this->_nodeList.begin();
145+
146+
// Iterate over all of the elements in the list L
147+
while (nodeUiterator != this->_nodeList.end())
148+
{
149+
// Get the height of current vertex
150+
int oldHeight = this->_height[*nodeUiterator];
151+
152+
// Discharge the excess flow of current vertex
153+
this->Discharge(*nodeUiterator);
154+
155+
// Check if the height of current vertex increases which means the current vertex got relabeled
156+
if (this->_height[*nodeUiterator] > oldHeight)
157+
{
158+
// Then move current vertex to the front of the list L
159+
this->_nodeList.splice(this->_nodeList.begin(), this->_nodeList, nodeUiterator);
160+
}
161+
162+
// Go to the next vertex of current vertex in L
163+
nodeUiterator++;
164+
}
165+
166+
// Return the excess flow in the sink vertex which is actually the maximum flow along the given flow network
167+
return this->_excessFlow[this->_sink];
168+
}
169+
}

SourceCodes/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ set(0003GRAPH_SOURCES
1818
0016_MaximumFlowEdmondsKarp.cc
1919
0017_MaximumBipartiteMatching.cc
2020
0018_MaximumFlowGoldbergGenericPushRelabel.cc
21+
0019_MaximumFlowRelabelToFront.cc
2122

2223
)
2324

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include<gtest/gtest.h>
2+
#include "../Headers/0003_Graph/0019_MaximumFlowRelabelToFront.h"
3+
#include "../0000_CommonUtilities/UnitTestHelper.h"
4+
using namespace std;
5+
6+
namespace MaximumFlowRelabelToFront
7+
{
8+
UnitTestHelper unitTestHelper;
9+
10+
TEST(MaximumFlowRelabelToFront, SimpleGraph)
11+
{
12+
// Arrange
13+
Graph graph;
14+
int noOfVertices = 6;
15+
int expectedMaximumFlow = 23;
16+
17+
18+
// Act
19+
graph.CreateGraph(noOfVertices);
20+
21+
graph.PushDirectedEdge(0, 1, 16);
22+
graph.PushDirectedEdge(0, 2, 13);
23+
graph.PushDirectedEdge(1, 3, 12);
24+
graph.PushDirectedEdge(2, 1, 4);
25+
graph.PushDirectedEdge(2, 4, 14);
26+
graph.PushDirectedEdge(3, 2, 9);
27+
graph.PushDirectedEdge(3, 5, 20);
28+
graph.PushDirectedEdge(4, 3, 7);
29+
graph.PushDirectedEdge(4, 5, 4);
30+
31+
int actualMaximumFlow = graph.FindMaximumFlowRelabelToFront();
32+
33+
// Assert
34+
ASSERT_EQ(expectedMaximumFlow, actualMaximumFlow);
35+
}
36+
}

Tests/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ add_executable(
3030
0016_MaximumFlowEdmondsKarpTest.cc
3131
0017_MaximumBipartiteMatchingTest.cc
3232
0018_MaximumFlowGoldbergGenericPushRelabelTest.cc
33+
0019_MaximumFlowRelabelToFrontTest.cc
3334
)
3435

3536
target_link_libraries(

0 commit comments

Comments
 (0)