Skip to content

Commit 78ad19c

Browse files
authored
Merge pull request #62 from Debashis08/feature-graph-implementation
Feature graph implementation
2 parents c00f23f + f75bfb1 commit 78ad19c

File tree

5 files changed

+242
-0
lines changed

5 files changed

+242
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
3+
#include<map>
4+
#include<vector>
5+
#include<queue>
6+
using namespace std;
7+
8+
namespace MaximumFlowGoldbergGenericPushRelabel
9+
{
10+
class Graph
11+
{
12+
private:
13+
int _noOfVertices;
14+
int _source;
15+
int _sink;
16+
int _maximumFlow;
17+
vector<vector<int>> _adjMatrix;
18+
vector<vector<int>> _residualGraph;
19+
vector<int> _excessFlow;
20+
vector<int> _height;
21+
vector<bool> _visited;
22+
queue<int> _nodeQueue;
23+
void InitializePreflow();
24+
bool CheckOverFlow();
25+
bool Push(int nodeU);
26+
void Relabel(int nodeU);
27+
public:
28+
void CreateGraph(int noOfVertices);
29+
void PushDirectedEdge(int valueU, int valueV, int capacity);
30+
int FindMaximumFlowGoldbergGenericPushRelabel();
31+
};
32+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#include "../Headers/0003_Graph/0018_MaximumFlowGoldbergGenericPushRelabel.h"
2+
#include<queue>
3+
#include<climits>
4+
using namespace std;
5+
6+
namespace MaximumFlowGoldbergGenericPushRelabel
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+
// Checks if there is any vertex which has excess flow
36+
bool Graph::CheckOverFlow()
37+
{
38+
// Iterating over all of the vertices
39+
for (int i = 0; i < this->_noOfVertices; i++)
40+
{
41+
// Checks if the current vertex is not any special vertex like source, sink
42+
// and also if there is excess flow in the current vertex and it is already not present in the queue
43+
if (i!=this->_source && i!=this->_sink && this->_excessFlow[i] > 0 && this->_visited[i] == false)
44+
{
45+
// Insert the current vertex into the queue
46+
this->_nodeQueue.push(i);
47+
48+
// Mark it as visited, so until it leaves the queue it is not inserted again even if all the excess flow is neutralized
49+
this->_visited[i] = true;
50+
}
51+
}
52+
53+
// Checks if there is no vertex having excess flow then returns false
54+
if (this->_nodeQueue.empty())
55+
{
56+
return false;
57+
}
58+
59+
return true;
60+
}
61+
62+
// Pushes the flow from nodeU to its neighbour vertices
63+
bool Graph::Push(int nodeU)
64+
{
65+
int nodeV = -1;
66+
int minimumFlow = INT_MAX;
67+
68+
// Iterating over all the vertices
69+
for (int i = 0; i < this->_noOfVertices; i++)
70+
{
71+
// For G'.Adj[nodeU] select the vertex if edge (nodeU, i) is non-saturated and height[nodeU] == height[i] + 1
72+
if (this->_residualGraph[nodeU][i] > 0 && this->_height[nodeU] == this->_height[i] + 1)
73+
{
74+
nodeV = i;
75+
break;
76+
}
77+
}
78+
79+
// Checks if any neighbour vertex found having non-saturated edge
80+
if (nodeV != -1)
81+
{
82+
// Calculate the flow amount to be added along the edge and excess flow subtracted from nodeU
83+
minimumFlow = min(this->_residualGraph[nodeU][nodeV], this->_excessFlow[nodeU]);
84+
85+
// Adjust the flow and the reverse flow along (nodeU, nodeV)
86+
this->_residualGraph[nodeU][nodeV] = this->_residualGraph[nodeU][nodeV] - minimumFlow;
87+
this->_residualGraph[nodeV][nodeU] = this->_residualGraph[nodeV][nodeU] + minimumFlow;
88+
89+
// Adjust the excess flows in nodeU and nodeV
90+
this->_excessFlow[nodeU] = this->_excessFlow[nodeU] - minimumFlow;
91+
this->_excessFlow[nodeV] = this->_excessFlow[nodeV] + minimumFlow;
92+
93+
// Return that the Push operation is successful
94+
return true;
95+
}
96+
97+
// Return that the Push operation is not successful
98+
return false;
99+
}
100+
101+
// Relabels height of vertex nodeU when there are outgoing non-saturated edges available
102+
void Graph::Relabel(int nodeU)
103+
{
104+
int minimumHeight = INT_MAX;
105+
106+
// Iterating over all the vertices
107+
for (int nodeV = 0; nodeV < this->_noOfVertices; nodeV++)
108+
{
109+
// For G'.Adj[nodeU] select for which nodeV, height[nodeU] <= height[nodeV]
110+
if (this->_residualGraph[nodeU][nodeV] > 0 && this->_height[nodeU] <= this->_height[nodeV])
111+
{
112+
// Get the minimum height among all these G'.Adj[nodeU]
113+
minimumHeight = min(minimumHeight, this->_height[nodeV]);
114+
}
115+
}
116+
117+
// Set height[nodeU]
118+
this->_height[nodeU] = minimumHeight + 1;
119+
}
120+
121+
122+
// Graph Public Member Methods
123+
void Graph::CreateGraph(int noOfVertices)
124+
{
125+
this->_noOfVertices = noOfVertices;
126+
this->_source = 0;
127+
this->_sink = this->_noOfVertices - 1;
128+
this->_maximumFlow = 0;
129+
this->_adjMatrix = vector<vector<int>>(this->_noOfVertices, vector<int>(this->_noOfVertices, 0));
130+
this->_excessFlow = vector<int>(this->_noOfVertices, 0);
131+
this->_height = vector<int>(this->_noOfVertices, 0);
132+
this->_visited = vector<bool>(this->_noOfVertices, false);
133+
}
134+
135+
void Graph::PushDirectedEdge(int valueU, int valueV, int capacity)
136+
{
137+
this->_adjMatrix[valueU][valueV] = capacity;
138+
}
139+
140+
int Graph::FindMaximumFlowGoldbergGenericPushRelabel()
141+
{
142+
this->_residualGraph = this->_adjMatrix;
143+
144+
// Initialize Pre-flow
145+
this->InitializePreflow();
146+
147+
// Checks if there is some vertices which have excess flow
148+
while (this->CheckOverFlow())
149+
{
150+
// Get the vertex
151+
int nodeU = this->_nodeQueue.front();
152+
153+
// Checks if the Push operation is successful
154+
if (this->Push(nodeU))
155+
{
156+
// Then remove the vertex from queue and set visited[nodeU] = true
157+
// so that on next CheckOverFlow() method call this vertex can be discovered if it still has some excess flow
158+
this->_nodeQueue.pop();
159+
this->_visited[nodeU] = false;
160+
}
161+
162+
// If the Push operation is not successful
163+
else
164+
{
165+
// Then Relabel nodeU without removing it from the queue
166+
this->Relabel(nodeU);
167+
}
168+
}
169+
170+
// Return the excess flow in the sink vertex which is actually the maximum flow along the given flow network
171+
return this->_excessFlow[this->_sink];
172+
}
173+
}

SourceCodes/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ set(0003GRAPH_SOURCES
1717
0015_MaximumFlowFordFulkerson.cc
1818
0016_MaximumFlowEdmondsKarp.cc
1919
0017_MaximumBipartiteMatching.cc
20+
0018_MaximumFlowGoldbergGenericPushRelabel.cc
2021

2122
)
2223

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

Tests/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_executable(
2929
0015_MaximumFlowFordFulkersonTest.cc
3030
0016_MaximumFlowEdmondsKarpTest.cc
3131
0017_MaximumBipartiteMatchingTest.cc
32+
0018_MaximumFlowGoldbergGenericPushRelabelTest.cc
3233
)
3334

3435
target_link_libraries(

0 commit comments

Comments
 (0)