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.

211 lines
8.4 KiB

  1. #include <algorithm>
  2. #include <iostream>
  3. #include <queue>
  4. #include <stack>
  5. #include <sstream>
  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. //if(!stdout_output && file_output) {
  12. // m_stdout_output = false;
  13. //} else {
  14. // m_stdout_output = true;
  15. //}
  16. }
  17. void Graph::parseFromString(const std::string &graph_string) {
  18. parser::parseString(graph_string, m_arc_list, m_vertices, m_source_id, m_sink_id, m_num_vertices, m_num_arcs);
  19. setSourceAndSinkIterator();
  20. initMatrices();
  21. initOstream();
  22. }
  23. void Graph::parseFromFile(const std::string &graph_file) {
  24. if(graph_file == m_output_file_name) {
  25. throw std::runtime_error("Input graph file name and output file name are the same. Will not overwrite. Exiting...");
  26. }
  27. parser::parseFile(graph_file, m_arc_list, m_vertices, m_source_id, m_sink_id, m_num_vertices, m_num_arcs);
  28. setSourceAndSinkIterator();
  29. initMatrices();
  30. initOstream();
  31. }
  32. void Graph::initMatrices() {
  33. m_flow.resize(m_num_vertices, std::vector<Capacity>(m_num_vertices, 0));
  34. m_capapcities.resize(m_num_vertices, std::vector<Capacity>(m_num_vertices, 0));
  35. for(auto const &arc : m_arc_list) {
  36. m_capapcities.at(arc.start - 1).at(arc.end - 1) = arc.capacity; // how to best map arbitrary ids to index in matrix
  37. }
  38. }
  39. void Graph::setSourceAndSinkIterator() {
  40. auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); });
  41. auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_sink_id); });
  42. }
  43. void Graph::initOstream() {
  44. if(m_file_output) {
  45. m_ofstream = new std::ofstream(m_output_file_name);
  46. } else {
  47. m_ofstream = &std::cout;
  48. }
  49. }
  50. void Graph::maxFlowDinic() {
  51. std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
  52. printInformation();
  53. do {
  54. constructLevelGraph();
  55. } while(findAugmentingPaths() != NO_AUGMENTING_PATH_FOUND);
  56. *m_ofstream << "Found max flow |x| = " << m_max_flow << "\n";
  57. if(m_verbose_max_flow) printMaxFlowInformation();
  58. if(m_min_cut) printMinCut();
  59. if(m_verbosity >= 1) printComputationStatistics(start, std::chrono::steady_clock::now());
  60. }
  61. int Graph::findAugmentingPaths() {
  62. auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return v.getID() == m_sink_id; });
  63. if(m_sink->getLevel() == UNDEF_LEVEL) {
  64. return NO_AUGMENTING_PATH_FOUND;
  65. }
  66. for(auto &v : m_vertices) {
  67. v.setVisited(false);
  68. }
  69. auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return v.getID() == m_source_id; });
  70. std::vector<Vertex> path{*m_source};
  71. buildPath(path);
  72. return 0;
  73. }
  74. void Graph::buildPath(std::vector<Vertex> &current_path) {
  75. Vertex head = current_path.back();
  76. if(head.getID() == m_sink_id) {
  77. computeFlowForPath(current_path);
  78. }
  79. for(auto const& arc : head.getOutgoingArcs()) {
  80. if(m_capapcities.at(arc.start - 1).at(arc.end - 1) <= 0) continue;
  81. auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [&arc] (const Vertex &v) { return v.getID() == arc.end; });
  82. if(head.getLevel() + 1 != it->getLevel()) continue;
  83. if(it != m_vertices.end()) {
  84. current_path.push_back(*it);
  85. buildPath(current_path);
  86. }
  87. current_path.pop_back();
  88. }
  89. if(m_verbosity >= 1) m_num_build_path_calls++;
  90. }
  91. void Graph::computeFlowForPath(const std::vector<Vertex> &current_path) {
  92. std::vector<Capacity> path_capacities;
  93. for(uint i = 0; i < current_path.size() - 1; i++) {
  94. path_capacities.push_back(m_capapcities.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1));
  95. }
  96. Capacity flow = *std::min_element(path_capacities.begin(), path_capacities.end());
  97. m_max_flow += flow;
  98. for(uint i = 0; i < current_path.size() - 1; i++) {
  99. m_capapcities.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1) -= flow;
  100. m_flow.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1) += flow;
  101. }
  102. if(m_verbosity >= 1) m_num_paths++;
  103. if(m_verbosity >= 2) {
  104. std::stringstream path;
  105. path << std::to_string(current_path.front().getID());
  106. for(uint i = 1; i < current_path.size(); i++) {
  107. path << " > " << current_path.at(i).getID();
  108. }
  109. path << " | flow = " << flow;
  110. m_augmenting_paths.push_back(path.str());
  111. }
  112. }
  113. void Graph::constructLevelGraph() {
  114. std::queue<Vertex> q;
  115. for(auto &v : m_vertices) {
  116. v.setLevel(UNDEF_LEVEL);
  117. }
  118. auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); });
  119. m_source->setLevel(0);
  120. q.push(*m_source);
  121. while(!q.empty()) {
  122. Vertex current_vertex = q.front();
  123. int current_level = current_vertex.getLevel();
  124. q.pop();
  125. // restructure this to use matrix
  126. for(auto const &arc : current_vertex.getOutgoingArcs()) {
  127. if(m_capapcities.at(arc.start - 1).at(arc.end - 1) <= 0) continue;
  128. auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [&arc] (const Vertex &v) { return (v.getID() == arc.end) && !v.hasDefinedLevel(); });
  129. if(it != m_vertices.end()) {
  130. it->setLevel(current_level + 1);
  131. q.push(*it);
  132. }
  133. }
  134. }
  135. if(m_verbosity >= 1) m_num_level_graphs_built++;
  136. }
  137. void Graph::printInformation() const {
  138. auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); });
  139. auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_sink_id); });
  140. *m_ofstream << "#Vertices: " << m_num_vertices << std::endl;
  141. *m_ofstream << "#Arc: " << m_num_arcs << std::endl;
  142. *m_ofstream << "Source: " << m_source->getID() << ", Sink: " << m_sink->getID() << std::endl;
  143. *m_ofstream << "Vertices: ";
  144. bool first = true;
  145. for(auto const& v : m_vertices) {
  146. if(first) first = false;
  147. else *m_ofstream << ", ";
  148. *m_ofstream << v.getID();
  149. }
  150. *m_ofstream << std::endl;
  151. for(auto const& a : m_arc_list) {
  152. *m_ofstream << " " << a.start << " -> " << a.end << " capacity = " << a.capacity << std::endl;
  153. }
  154. *m_ofstream << std::endl;
  155. }
  156. void Graph::printMaxFlowInformation() const {
  157. *m_ofstream << "Max Flow per arc:\n";
  158. for(auto const &arc : m_arc_list) {
  159. *m_ofstream << " " << arc.start << " -> " << arc.end << " flow = " << m_flow.at(arc.start - 1 ).at(arc.end - 1) << "/" << arc.capacity << "\n";
  160. }
  161. }
  162. void Graph::printMinCut() const {
  163. std::vector<std::string> min_cut, complement;
  164. for(auto const &vertex : m_vertices) {
  165. if(vertex.getLevel() != UNDEF_LEVEL) {
  166. min_cut.push_back(std::to_string(vertex.getID()));
  167. } else {
  168. complement.push_back(std::to_string(vertex.getID()));
  169. }
  170. }
  171. *m_ofstream << "Min Cut X: {";
  172. bool first = true;
  173. for(auto const &v : min_cut) {
  174. if(first) first = false;
  175. else *m_ofstream << ", ";
  176. *m_ofstream << v;
  177. } *m_ofstream << "}\nComplement(X): {";
  178. first = true;
  179. for(auto const &v : complement) {
  180. if(first) first = false;
  181. else *m_ofstream << ", ";
  182. *m_ofstream << v;
  183. } *m_ofstream << "}\n";
  184. }
  185. void Graph::printComputationStatistics(const std::chrono::steady_clock::time_point &start, const std::chrono::steady_clock::time_point &end) const {
  186. *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";
  187. *m_ofstream << "Computation Statistics:\n";
  188. *m_ofstream << " #level graphs built: " << m_num_level_graphs_built << "\n";
  189. *m_ofstream << " #augmenting paths computed: " << m_num_paths << "\n";
  190. if(m_verbosity >= 2) {
  191. for(auto const &path : m_augmenting_paths) *m_ofstream << " " << path << "\n";
  192. }
  193. *m_ofstream << " #recursive buildPath calls: " << m_num_build_path_calls << "\n";
  194. }
  195. }