A simple students project implementing Dinic's Algorithm to compute the max flow/min cut of a network.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
14 KiB

  1. #include <algorithm>
  2. #include <iostream>
  3. #include <queue>
  4. #include <sstream>
  5. #include <climits>
  6. #include "Graph.h"
  7. #include "util/GraphParser.h"
  8. namespace data {
  9. Graph::Graph(bool stdout_output, bool file_output, std::string output_filename, bool verbose_max_flow, bool min_cut, int verbosity)
  10. : m_file_output(file_output), m_output_file_name(output_filename), m_verbose_max_flow(verbose_max_flow), m_min_cut(min_cut), m_verbosity(verbosity) {
  11. }
  12. void Graph::parseFromString(const std::string &graph_string) {
  13. parser::parseString(graph_string, m_arc_list, m_vertices, m_source_id, m_sink_id, m_num_vertices, m_num_arcs);
  14. initMatrices();
  15. initOstream();
  16. }
  17. void Graph::parseFromFile(const std::string &graph_file) {
  18. if(graph_file == m_output_file_name) {
  19. throw std::runtime_error("Input graph file name and output file name are the same. Will not overwrite. Exiting...");
  20. }
  21. parser::parseFile(graph_file, m_arc_list, m_vertices, m_source_id, m_sink_id, m_num_vertices, m_num_arcs);
  22. initMatrices();
  23. initOstream();
  24. }
  25. void Graph::initMatrices() {
  26. m_flow.resize(m_num_vertices, std::vector<Capacity>(m_num_vertices, 0));
  27. m_capapcities.resize(m_num_vertices, std::vector<Capacity>(m_num_vertices, 0));
  28. for(auto const &arc : m_arc_list) {
  29. m_capapcities.at(arc.start - 1).at(arc.end - 1) += arc.capacity;
  30. }
  31. m_network = m_capapcities;
  32. }
  33. void Graph::initOstream() {
  34. if(m_file_output) {
  35. m_ofstream = new std::ofstream(m_output_file_name);
  36. } else {
  37. m_ofstream = &std::cout;
  38. }
  39. }
  40. int Graph::maxFlowDinic() {
  41. std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
  42. printInformation();
  43. do {
  44. constructLevelGraph();
  45. } while(findAugmentingPaths() != NO_AUGMENTING_PATH_FOUND);
  46. *m_ofstream << "Found max flow |x| = " << m_max_flow << "\n";
  47. if(m_verbose_max_flow) printMaxFlowInformation();
  48. if(m_min_cut) printMinCut();
  49. if(m_verbosity >= 1) printComputationStatistics(start, std::chrono::steady_clock::now());
  50. return m_max_flow;
  51. }
  52. int Graph::findAugmentingPaths() {
  53. auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return v.getID() == m_sink_id; });
  54. if(m_sink->getLevel() == UNDEF_LEVEL) {
  55. return NO_AUGMENTING_PATH_FOUND;
  56. }
  57. for(auto &v : m_vertices) {
  58. v.setVisited(false);
  59. }
  60. auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return v.getID() == m_source_id; });
  61. std::vector<Vertex> path{*m_source};
  62. buildPath(path);
  63. return 0;
  64. }
  65. void Graph::buildPath(std::vector<Vertex> &current_path) {
  66. Vertex head = current_path.back();
  67. if(head.getID() == m_sink_id) {
  68. computeFlowForPath(current_path);
  69. }
  70. for(auto const& arc : head.getOutgoingArcs()) {
  71. if(m_capapcities.at(arc.start - 1).at(arc.end - 1) <= 0) continue;
  72. auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [&arc] (const Vertex &v) { return v.getID() == arc.end; });
  73. if(head.getLevel() + 1 != it->getLevel()) continue;
  74. if(it != m_vertices.end()) {
  75. current_path.push_back(*it);
  76. buildPath(current_path);
  77. }
  78. current_path.pop_back();
  79. }
  80. if(m_verbosity >= 1) m_num_build_path_calls++;
  81. }
  82. void Graph::computeFlowForPath(const std::vector<Vertex> &current_path) {
  83. std::vector<Capacity> path_capacities;
  84. for(uint i = 0; i < current_path.size() - 1; i++) {
  85. path_capacities.push_back(m_capapcities.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1));
  86. }
  87. Capacity flow = *std::min_element(path_capacities.begin(), path_capacities.end());
  88. m_max_flow += flow;
  89. for(uint i = 0; i < current_path.size() - 1; i++) {
  90. m_capapcities.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1) -= flow;
  91. m_flow.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1) += flow;
  92. }
  93. if(m_verbosity >= 1) m_num_paths++;
  94. if(m_verbosity >= 2) {
  95. std::stringstream path;
  96. path << std::to_string(current_path.front().getID());
  97. for(uint i = 1; i < current_path.size(); i++) {
  98. path << " > " << current_path.at(i).getID();
  99. }
  100. path << " | flow = " << flow;
  101. m_augmenting_paths.push_back(path.str());
  102. }
  103. }
  104. void Graph::constructLevelGraph() {
  105. std::queue<Vertex> q;
  106. for(auto &v : m_vertices) {
  107. v.setLevel(UNDEF_LEVEL);
  108. }
  109. auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); });
  110. m_source->setLevel(0);
  111. q.push(*m_source);
  112. while(!q.empty()) {
  113. Vertex current_vertex = q.front();
  114. int current_level = current_vertex.getLevel();
  115. q.pop();
  116. // restructure this to use matrix
  117. for(auto const &arc : current_vertex.getOutgoingArcs()) {
  118. if(m_capapcities.at(arc.start - 1).at(arc.end - 1) <= 0) continue;
  119. auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [&arc] (const Vertex &v) { return (v.getID() == arc.end) && !v.hasDefinedLevel(); });
  120. if(it != m_vertices.end()) {
  121. it->setLevel(current_level + 1);
  122. q.push(*it);
  123. }
  124. }
  125. }
  126. if(m_verbosity >= 1) m_num_level_graphs_built++;
  127. }
  128. void Graph::hasUniqueMaxFlow() {
  129. *m_ofstream << "\nChecking uniqueness of maximum flow:\n";
  130. CapacityMatrix residualGraph = m_capapcities;
  131. for(uint row = 0; row < m_flow.size(); row++) {
  132. for(uint i = 0; i < m_flow.at(0).size(); i++) {
  133. residualGraph.at(i).at(row) += m_flow.at(row).at(i);
  134. }
  135. }
  136. int visited[m_num_vertices];
  137. std::stack<int> *recursive_stack = new std::stack<int>();
  138. bool found_cycle = false;
  139. for(uint i = 0; i < m_num_vertices; i++){
  140. visited[i] = NOT_PROCESSED;
  141. }
  142. for(uint i = 0; i < m_num_vertices; i++){
  143. if(visited[i] == NOT_PROCESSED) {
  144. visited[i] = ON_STACK;
  145. recursive_stack = new std::stack<int>();
  146. recursive_stack->push(i);
  147. isResidualGraphCyclic(residualGraph, visited, INVALID_VERTEX, recursive_stack, found_cycle);
  148. }
  149. }
  150. if(!found_cycle) *m_ofstream << "The max flow is unique!\n";
  151. }
  152. void Graph::isResidualGraphCyclic(const CapacityMatrix &residual_graph, int *visited, const int previous, std::stack<int> *recursive_stack, bool &found_cycle) {
  153. int top = recursive_stack->top();
  154. for(uint next = 0; next < residual_graph.at(top).size(); next++) {
  155. if(next == previous) continue;
  156. if(residual_graph.at(top).at(next) == 0) continue;
  157. //std::cout << "prev, top, next, capacity: " << previous +1 << ", " << top +1 << ", " << next+1 << ", " << residual_graph.at(top).at(next) <<std::endl;
  158. if(visited[next] == NOT_PROCESSED || visited[next] == PROCESSED) {
  159. recursive_stack->push(next);
  160. visited[next] = ON_STACK;
  161. isResidualGraphCyclic(residual_graph, visited, top, recursive_stack, found_cycle);
  162. } else if(visited[next] == ON_STACK) {
  163. if(recursive_stack->size() >= 3) {
  164. found_cycle = true;
  165. printCycle(residual_graph, recursive_stack);
  166. }
  167. }
  168. }
  169. visited[top] = PROCESSED;
  170. recursive_stack->pop();
  171. }
  172. void Graph::printCycle(const CapacityMatrix residual_matrix, std::stack<int> *stack) {
  173. int first, previous, current;
  174. std::stack<int> print_stack;
  175. while(stack->size() != 0) {
  176. print_stack.push(stack->top());
  177. stack->pop();
  178. }
  179. previous = print_stack.top();
  180. first = previous;
  181. print_stack.pop();
  182. *m_ofstream << previous + 1;
  183. int min_capacity = INT_MAX;
  184. while(print_stack.size() != 0) {
  185. current = print_stack.top();
  186. *m_ofstream << " -> " << current + 1;
  187. if(residual_matrix.at(previous).at(current) < min_capacity) min_capacity = residual_matrix.at(previous).at(current);
  188. print_stack.pop();
  189. stack->push(current);
  190. previous = current;
  191. }
  192. *m_ofstream << " -> " << first + 1;
  193. if(residual_matrix.at(current).at(first) < min_capacity) min_capacity = residual_matrix.at(current).at(first);
  194. *m_ofstream << ", where " << min_capacity << " unit";
  195. if(min_capacity > 1) *m_ofstream << "s";
  196. *m_ofstream << " of flow could be shifted." << std::endl;
  197. }
  198. void Graph::hasUniqueMinCut() {
  199. *m_ofstream << "\nChecking uniqueness of minimum cut:\n";
  200. std::vector<Arc> *cut_edges = new std::vector<Arc>();
  201. computeMinCut(nullptr, nullptr, cut_edges);
  202. bool found_another_min_cut = false;
  203. for(auto const &arc : *cut_edges) {
  204. Graph augmented_network = *this;
  205. augmented_network.incrementArcCapacity(arc.start - 1, arc.end - 1);
  206. augmented_network.resetNetwork();
  207. augmented_network.disableOutput();
  208. int augmented_max_flow = augmented_network.maxFlowDinic();
  209. augmented_network.enableOutput();
  210. if(augmented_max_flow == m_max_flow) {
  211. found_another_min_cut = true;
  212. *m_ofstream << "Found another minimum cut after incrementing (" << arc.start << "," << arc.end << ") with a flow value of " << augmented_max_flow << "." << std::endl;
  213. augmented_network.printMinCut();
  214. //augmented_network.hasUniqueMinCut();
  215. }
  216. }
  217. if(!found_another_min_cut) {
  218. *m_ofstream << "The minimum cut is unique!\n";
  219. }
  220. }
  221. void Graph::printInformation() const {
  222. auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); });
  223. auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_sink_id); });
  224. *m_ofstream << "#Vertices: " << m_num_vertices << std::endl;
  225. *m_ofstream << "#Arc: " << m_num_arcs << std::endl;
  226. *m_ofstream << "Source: " << m_source->getID() << ", Sink: " << m_sink->getID() << std::endl;
  227. *m_ofstream << "Vertices: ";
  228. bool first = true;
  229. for(auto const& v : m_vertices) {
  230. if(first) first = false;
  231. else *m_ofstream << ", ";
  232. *m_ofstream << v.getID();
  233. }
  234. *m_ofstream << std::endl;
  235. for(auto const& a : m_arc_list) {
  236. *m_ofstream << " " << a.start << " -> " << a.end << " capacity = " << a.capacity << std::endl;
  237. }
  238. *m_ofstream << std::endl;
  239. }
  240. void Graph::printMaxFlowInformation() const {
  241. *m_ofstream << "Max Flow per arc:\n";
  242. for(auto const &arc : m_arc_list) {
  243. *m_ofstream << " " << arc.start << " -> " << arc.end << " flow = " << m_flow.at(arc.start - 1 ).at(arc.end - 1) << "/" << arc.capacity << "\n";
  244. }
  245. }
  246. void Graph::computeMinCut(std::vector<Vertex> *source_vertices, std::vector<Vertex> *sink_vertices, std::vector<Arc> *cut_edges) const {
  247. if(!source_vertices) source_vertices = new std::vector<Vertex>();
  248. if(!sink_vertices) sink_vertices = new std::vector<Vertex>();
  249. for(auto const &vertex : m_vertices) {
  250. if(vertex.getLevel() != UNDEF_LEVEL) {
  251. source_vertices->push_back(vertex.getID());
  252. } else {
  253. sink_vertices->push_back(vertex.getID());
  254. }
  255. }
  256. if(cut_edges) {
  257. for(auto const source : *source_vertices) {
  258. for(auto const sink : *sink_vertices) {
  259. int capacity = m_network.at(source.getID() - 1).at(sink.getID() - 1);
  260. if(capacity > 0) {
  261. cut_edges->push_back({source.getID(), sink.getID(), capacity, capacity, 0});
  262. }
  263. }
  264. }
  265. }
  266. }
  267. void Graph::printMinCut() const {
  268. std::vector<Arc> *arcs = new std::vector<Arc>();
  269. std::vector<Vertex> *source_vertices = new std::vector<Vertex>();
  270. std::vector<Vertex> *sink_vertices = new std::vector<Vertex>();
  271. computeMinCut(source_vertices, sink_vertices, arcs);
  272. std::vector<std::string> min_cut, complement;
  273. for(auto const &vertex : *source_vertices) {
  274. min_cut.push_back(std::to_string(vertex.getID()));
  275. }
  276. for(auto const &vertex : *sink_vertices) {
  277. complement.push_back(std::to_string(vertex.getID()));
  278. }
  279. *m_ofstream << "Min Cut X: {";
  280. bool first = true;
  281. for(auto const &v : min_cut) {
  282. if(first) first = false;
  283. else *m_ofstream << ", ";
  284. *m_ofstream << v;
  285. } *m_ofstream << "}\nComplement(X): {";
  286. first = true;
  287. for(auto const &v : complement) {
  288. if(first) first = false;
  289. else *m_ofstream << ", ";
  290. *m_ofstream << v;
  291. } *m_ofstream << "}\n";
  292. }
  293. void Graph::printComputationStatistics(const std::chrono::steady_clock::time_point &start, const std::chrono::steady_clock::time_point &end) const {
  294. *m_ofstream << "Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms (" << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "µs).\n";
  295. *m_ofstream << "Computation Statistics:\n";
  296. *m_ofstream << " #level graphs built: " << m_num_level_graphs_built << "\n";
  297. *m_ofstream << " #augmenting paths computed: " << m_num_paths << "\n";
  298. if(m_verbosity >= 2) {
  299. for(auto const &path : m_augmenting_paths) *m_ofstream << " " << path << "\n";
  300. }
  301. *m_ofstream << " #recursive buildPath calls: " << m_num_build_path_calls << "\n";
  302. }
  303. void Graph::incrementArcCapacity(const int source, const int sink) {
  304. m_network.at(source).at(sink)++;
  305. }
  306. void Graph::resetNetwork() {
  307. m_max_flow = 0;
  308. m_capapcities = m_network;
  309. }
  310. void Graph::disableOutput() {
  311. m_ofstream->setstate(std::ios_base::badbit);
  312. }
  313. void Graph::enableOutput() {
  314. m_ofstream->clear();
  315. }
  316. void Graph::printMatrices() const {
  317. //for(auto const row : m_flow) {
  318. // for(auto const i : row) {
  319. // std::cout << i << " ";
  320. // } std::cout << std::endl;
  321. //}
  322. std::cout << std::endl;
  323. for(auto const row : m_network) {
  324. for(auto const i : row) {
  325. std::cout << i << " ";
  326. } std::cout << std::endl;
  327. }
  328. std::cout << std::endl;
  329. for(auto const row : m_capapcities) {
  330. for(auto const i : row) {
  331. std::cout << i << " ";
  332. } std::cout << std::endl;
  333. }
  334. std::cout << std::endl;
  335. }
  336. }