Stefan Pranger
3 years ago
commit
bc203ea9c5
14 changed files with 1945 additions and 0 deletions
-
1.gitignore
-
27CMakeLists.txt
-
211Graph.cpp
-
70Graph.h
-
57main.cpp
-
13util/Arc.h
-
7util/CMakeLists.txt
-
76util/GraphParser.cpp
-
16util/GraphParser.h
-
54util/OptionParser.cpp
-
15util/OptionParser.h
-
35util/Vertex.cpp
-
32util/Vertex.h
-
1331util/popl.hpp
@ -0,0 +1 @@ |
|||||
|
build/ |
@ -0,0 +1,27 @@ |
|||||
|
include(util/CMakeLists.txt) |
||||
|
|
||||
|
set(CMAKE_CXX_STANDARD 17) |
||||
|
|
||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") |
||||
|
#add_definitions(-DLOG_DEBUG) |
||||
|
|
||||
|
cmake_minimum_required(VERSION 3.0...3.22) |
||||
|
|
||||
|
set(CMAKE_BUILD_TYPE Debug) |
||||
|
|
||||
|
project( |
||||
|
max_flow |
||||
|
VERSION 1.0 |
||||
|
LANGUAGES CXX) |
||||
|
|
||||
|
#find_package(Boost COMPONENTS program_options REQUIRED) |
||||
|
|
||||
|
#include_directories("." db exceptions) |
||||
|
|
||||
|
add_executable(maxFlow |
||||
|
${SRCS} |
||||
|
main.cpp |
||||
|
Graph.cpp |
||||
|
) |
||||
|
|
||||
|
target_link_libraries(maxFlow stdc++fs) |
@ -0,0 +1,211 @@ |
|||||
|
#include <algorithm>
|
||||
|
#include <iostream>
|
||||
|
#include <queue>
|
||||
|
#include <stack>
|
||||
|
#include <sstream>
|
||||
|
|
||||
|
#include "Graph.h"
|
||||
|
#include "util/GraphParser.h"
|
||||
|
|
||||
|
namespace data { |
||||
|
Graph::Graph(bool stdout_output, bool file_output, std::string output_filename, bool verbose_max_flow, bool min_cut, int verbosity) |
||||
|
: 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) { |
||||
|
//if(!stdout_output && file_output) {
|
||||
|
// m_stdout_output = false;
|
||||
|
//} else {
|
||||
|
// m_stdout_output = true;
|
||||
|
//}
|
||||
|
} |
||||
|
|
||||
|
void Graph::parseFromString(const std::string &graph_string) { |
||||
|
parser::parseString(graph_string, m_arc_list, m_vertices, m_source_id, m_sink_id, m_num_vertices, m_num_arcs); |
||||
|
setSourceAndSinkIterator(); |
||||
|
initMatrices(); |
||||
|
initOstream(); |
||||
|
} |
||||
|
|
||||
|
void Graph::parseFromFile(const std::string &graph_file) { |
||||
|
if(graph_file == m_output_file_name) { |
||||
|
throw std::runtime_error("Input graph file name and output file name are the same. Will not overwrite. Exiting..."); |
||||
|
} |
||||
|
parser::parseFile(graph_file, m_arc_list, m_vertices, m_source_id, m_sink_id, m_num_vertices, m_num_arcs); |
||||
|
setSourceAndSinkIterator(); |
||||
|
initMatrices(); |
||||
|
initOstream(); |
||||
|
} |
||||
|
|
||||
|
void Graph::initMatrices() { |
||||
|
m_flow.resize(m_num_vertices, std::vector<Capacity>(m_num_vertices, 0)); |
||||
|
m_capapcities.resize(m_num_vertices, std::vector<Capacity>(m_num_vertices, 0)); |
||||
|
for(auto const &arc : m_arc_list) { |
||||
|
m_capapcities.at(arc.start - 1).at(arc.end - 1) = arc.capacity; // how to best map arbitrary ids to index in matrix
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Graph::setSourceAndSinkIterator() { |
||||
|
auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); }); |
||||
|
auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_sink_id); }); |
||||
|
} |
||||
|
|
||||
|
void Graph::initOstream() { |
||||
|
if(m_file_output) { |
||||
|
m_ofstream = new std::ofstream(m_output_file_name); |
||||
|
} else { |
||||
|
m_ofstream = &std::cout; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Graph::maxFlowDinic() { |
||||
|
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); |
||||
|
printInformation(); |
||||
|
do { |
||||
|
constructLevelGraph(); |
||||
|
} while(findAugmentingPaths() != NO_AUGMENTING_PATH_FOUND); |
||||
|
*m_ofstream << "Found max flow |x| = " << m_max_flow << "\n"; |
||||
|
if(m_verbose_max_flow) printMaxFlowInformation(); |
||||
|
if(m_min_cut) printMinCut(); |
||||
|
if(m_verbosity >= 1) printComputationStatistics(start, std::chrono::steady_clock::now()); |
||||
|
} |
||||
|
|
||||
|
int Graph::findAugmentingPaths() { |
||||
|
auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return v.getID() == m_sink_id; }); |
||||
|
if(m_sink->getLevel() == UNDEF_LEVEL) { |
||||
|
return NO_AUGMENTING_PATH_FOUND; |
||||
|
} |
||||
|
for(auto &v : m_vertices) { |
||||
|
v.setVisited(false); |
||||
|
} |
||||
|
auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return v.getID() == m_source_id; }); |
||||
|
std::vector<Vertex> path{*m_source}; |
||||
|
buildPath(path); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void Graph::buildPath(std::vector<Vertex> ¤t_path) { |
||||
|
Vertex head = current_path.back(); |
||||
|
if(head.getID() == m_sink_id) { |
||||
|
computeFlowForPath(current_path); |
||||
|
} |
||||
|
for(auto const& arc : head.getOutgoingArcs()) { |
||||
|
if(m_capapcities.at(arc.start - 1).at(arc.end - 1) <= 0) continue; |
||||
|
auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [&arc] (const Vertex &v) { return v.getID() == arc.end; }); |
||||
|
if(head.getLevel() + 1 != it->getLevel()) continue; |
||||
|
if(it != m_vertices.end()) { |
||||
|
current_path.push_back(*it); |
||||
|
buildPath(current_path); |
||||
|
} |
||||
|
current_path.pop_back(); |
||||
|
} |
||||
|
if(m_verbosity >= 1) m_num_build_path_calls++; |
||||
|
} |
||||
|
|
||||
|
void Graph::computeFlowForPath(const std::vector<Vertex> ¤t_path) { |
||||
|
std::vector<Capacity> path_capacities; |
||||
|
for(uint i = 0; i < current_path.size() - 1; i++) { |
||||
|
path_capacities.push_back(m_capapcities.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1)); |
||||
|
} |
||||
|
Capacity flow = *std::min_element(path_capacities.begin(), path_capacities.end()); |
||||
|
m_max_flow += flow; |
||||
|
for(uint i = 0; i < current_path.size() - 1; i++) { |
||||
|
m_capapcities.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1) -= flow; |
||||
|
m_flow.at(current_path.at(i).getID() - 1).at(current_path.at(i + 1).getID() - 1) += flow; |
||||
|
} |
||||
|
if(m_verbosity >= 1) m_num_paths++; |
||||
|
if(m_verbosity >= 2) { |
||||
|
std::stringstream path; |
||||
|
path << std::to_string(current_path.front().getID()); |
||||
|
for(uint i = 1; i < current_path.size(); i++) { |
||||
|
path << " > " << current_path.at(i).getID(); |
||||
|
} |
||||
|
path << " | flow = " << flow; |
||||
|
m_augmenting_paths.push_back(path.str()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Graph::constructLevelGraph() { |
||||
|
std::queue<Vertex> q; |
||||
|
for(auto &v : m_vertices) { |
||||
|
v.setLevel(UNDEF_LEVEL); |
||||
|
} |
||||
|
auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); }); |
||||
|
m_source->setLevel(0); |
||||
|
q.push(*m_source); |
||||
|
while(!q.empty()) { |
||||
|
Vertex current_vertex = q.front(); |
||||
|
int current_level = current_vertex.getLevel(); |
||||
|
q.pop(); |
||||
|
// restructure this to use matrix
|
||||
|
for(auto const &arc : current_vertex.getOutgoingArcs()) { |
||||
|
if(m_capapcities.at(arc.start - 1).at(arc.end - 1) <= 0) continue; |
||||
|
auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [&arc] (const Vertex &v) { return (v.getID() == arc.end) && !v.hasDefinedLevel(); }); |
||||
|
if(it != m_vertices.end()) { |
||||
|
it->setLevel(current_level + 1); |
||||
|
q.push(*it); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if(m_verbosity >= 1) m_num_level_graphs_built++; |
||||
|
} |
||||
|
|
||||
|
void Graph::printInformation() const { |
||||
|
auto m_source = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_source_id); }); |
||||
|
auto m_sink = std::find_if(m_vertices.begin(), m_vertices.end(), [this] (const Vertex &v) { return (v.getID() == m_sink_id); }); |
||||
|
*m_ofstream << "#Vertices: " << m_num_vertices << std::endl; |
||||
|
*m_ofstream << "#Arc: " << m_num_arcs << std::endl; |
||||
|
*m_ofstream << "Source: " << m_source->getID() << ", Sink: " << m_sink->getID() << std::endl; |
||||
|
*m_ofstream << "Vertices: "; |
||||
|
bool first = true; |
||||
|
for(auto const& v : m_vertices) { |
||||
|
if(first) first = false; |
||||
|
else *m_ofstream << ", "; |
||||
|
*m_ofstream << v.getID(); |
||||
|
} |
||||
|
*m_ofstream << std::endl; |
||||
|
for(auto const& a : m_arc_list) { |
||||
|
*m_ofstream << " " << a.start << " -> " << a.end << " capacity = " << a.capacity << std::endl; |
||||
|
} |
||||
|
*m_ofstream << std::endl; |
||||
|
} |
||||
|
|
||||
|
void Graph::printMaxFlowInformation() const { |
||||
|
*m_ofstream << "Max Flow per arc:\n"; |
||||
|
for(auto const &arc : m_arc_list) { |
||||
|
*m_ofstream << " " << arc.start << " -> " << arc.end << " flow = " << m_flow.at(arc.start - 1 ).at(arc.end - 1) << "/" << arc.capacity << "\n"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Graph::printMinCut() const { |
||||
|
std::vector<std::string> min_cut, complement; |
||||
|
for(auto const &vertex : m_vertices) { |
||||
|
if(vertex.getLevel() != UNDEF_LEVEL) { |
||||
|
min_cut.push_back(std::to_string(vertex.getID())); |
||||
|
} else { |
||||
|
complement.push_back(std::to_string(vertex.getID())); |
||||
|
} |
||||
|
} |
||||
|
*m_ofstream << "Min Cut X: {"; |
||||
|
bool first = true; |
||||
|
for(auto const &v : min_cut) { |
||||
|
if(first) first = false; |
||||
|
else *m_ofstream << ", "; |
||||
|
*m_ofstream << v; |
||||
|
} *m_ofstream << "}\nComplement(X): {"; |
||||
|
first = true; |
||||
|
for(auto const &v : complement) { |
||||
|
if(first) first = false; |
||||
|
else *m_ofstream << ", "; |
||||
|
*m_ofstream << v; |
||||
|
} *m_ofstream << "}\n"; |
||||
|
} |
||||
|
|
||||
|
void Graph::printComputationStatistics(const std::chrono::steady_clock::time_point &start, const std::chrono::steady_clock::time_point &end) const { |
||||
|
*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"; |
||||
|
*m_ofstream << "Computation Statistics:\n"; |
||||
|
*m_ofstream << " #level graphs built: " << m_num_level_graphs_built << "\n"; |
||||
|
*m_ofstream << " #augmenting paths computed: " << m_num_paths << "\n"; |
||||
|
if(m_verbosity >= 2) { |
||||
|
for(auto const &path : m_augmenting_paths) *m_ofstream << " " << path << "\n"; |
||||
|
} |
||||
|
*m_ofstream << " #recursive buildPath calls: " << m_num_build_path_calls << "\n"; |
||||
|
} |
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <chrono> |
||||
|
#include <vector> |
||||
|
#include <set> |
||||
|
#include <string> |
||||
|
#include <fstream> |
||||
|
#include <iostream> |
||||
|
|
||||
|
#include "util/GraphParser.h" |
||||
|
#include "util/Arc.h" |
||||
|
|
||||
|
#define NO_AUGMENTING_PATH_FOUND -1 |
||||
|
|
||||
|
typedef std::vector<std::vector<Capacity>> CapacityMatrix; |
||||
|
|
||||
|
namespace data { |
||||
|
class Graph { |
||||
|
public: |
||||
|
Graph(bool stdout_output, bool file_output, std::string output_filename, bool verbose_max_flow, bool min_cut, int verbosity); |
||||
|
|
||||
|
void parseFromString(const std::string &graph_string); |
||||
|
void parseFromFile(const std::string &graph_file); |
||||
|
|
||||
|
void maxFlowDinic(); |
||||
|
|
||||
|
private: |
||||
|
void initMatrices(); |
||||
|
void setSourceAndSinkIterator(); |
||||
|
void initOstream(); |
||||
|
|
||||
|
void constructLevelGraph(); |
||||
|
int findAugmentingPaths(); |
||||
|
void buildPath(std::vector<Vertex> ¤t_path); |
||||
|
void computeFlowForPath(const std::vector<Vertex> ¤t_path); |
||||
|
|
||||
|
void printInformation() const; |
||||
|
void printMaxFlowInformation() const; |
||||
|
void printMinCut() const; |
||||
|
void printComputationStatistics(const std::chrono::steady_clock::time_point &start, const std::chrono::steady_clock::time_point &end) const; |
||||
|
|
||||
|
std::vector<Vertex> m_vertices; |
||||
|
std::vector<Arc> m_arc_list; |
||||
|
VertexID m_source_id; |
||||
|
VertexID m_sink_id; |
||||
|
std::vector<Vertex>::iterator m_source; |
||||
|
std::vector<Vertex>::iterator m_sink; |
||||
|
|
||||
|
CapacityMatrix m_flow; |
||||
|
CapacityMatrix m_capapcities; |
||||
|
|
||||
|
int m_num_vertices; |
||||
|
int m_num_arcs; |
||||
|
|
||||
|
int m_max_flow = 0; |
||||
|
|
||||
|
bool m_stdout_output = true; |
||||
|
bool m_file_output = false; |
||||
|
std::string m_output_file_name; |
||||
|
std::ostream *m_ofstream; |
||||
|
bool m_verbose_max_flow = false; |
||||
|
bool m_min_cut = false; |
||||
|
int m_verbosity = 0; |
||||
|
|
||||
|
uint m_num_paths = 0; |
||||
|
uint m_num_build_path_calls = 0; |
||||
|
uint m_num_level_graphs_built = 0; |
||||
|
std::vector<std::string> m_augmenting_paths; |
||||
|
}; |
||||
|
} |
@ -0,0 +1,57 @@ |
|||||
|
#include <iostream>
|
||||
|
#include <string>
|
||||
|
|
||||
|
#include "util/OptionParser.h"
|
||||
|
#include "Graph.h"
|
||||
|
|
||||
|
int main(int argc, char* argv[]) { |
||||
|
popl::OptionParser optionParser("Allowed options"); |
||||
|
|
||||
|
auto help_option = optionParser.add<popl::Switch>("h", "help", "Print this help message."); |
||||
|
auto input_filename = optionParser.add<popl::Value<std::string>, popl::Attribute::optional>("f", "input-file", "Filename of input graph file."); |
||||
|
auto input_string = optionParser.add<popl::Value<std::string>, popl::Attribute::optional>("s", "input-string", "Input graph string."); |
||||
|
|
||||
|
auto stdout_output = optionParser.add<popl::Switch, popl::Attribute::optional>("o", "stdout", "Output to stdout."); |
||||
|
auto file_output = optionParser.add<popl::Value<std::string>, popl::Attribute::optional>("p", "output-file", "Filename for output."); |
||||
|
|
||||
|
auto verbose_max_flow = optionParser.add<popl::Switch, popl::Attribute::optional>("a", "max-flow", "Include verbose information about the max flow to the output."); |
||||
|
auto min_cut_option = optionParser.add<popl::Switch, popl::Attribute::optional>("m", "minimum-cut", "Include the minimum cut set to the output."); |
||||
|
|
||||
|
auto verbose_option = optionParser.add<popl::Switch, popl::Attribute::optional>("v", "verbose", "Output verbose algorithmic information and runtime. Pass twice to get step-by-step information."); |
||||
|
|
||||
|
try { |
||||
|
optionParser.parse(argc, argv); |
||||
|
if(parser::checkOption(input_filename->count(), input_string->count()) > 0) { |
||||
|
std::cout << optionParser << std::endl; |
||||
|
return EXIT_FAILURE; |
||||
|
} |
||||
|
|
||||
|
if(help_option->count() > 0) { |
||||
|
std::cout << optionParser << std::endl; |
||||
|
} |
||||
|
} catch (const popl::invalid_option &e) { |
||||
|
return parser::printPoplException(e); |
||||
|
} catch (const std::exception &e) { |
||||
|
std::cerr << "Exception: " << e.what() << "\n"; |
||||
|
return EXIT_FAILURE; |
||||
|
} |
||||
|
|
||||
|
std::string filename = ""; |
||||
|
if(file_output->is_set()) { |
||||
|
filename = file_output->value(0); |
||||
|
} |
||||
|
data::Graph network(stdout_output->is_set(), |
||||
|
file_output->is_set(), |
||||
|
filename, |
||||
|
verbose_max_flow->is_set(), |
||||
|
min_cut_option->is_set(), |
||||
|
verbose_option->count()); |
||||
|
if(input_filename->count() > 0) { |
||||
|
network.parseFromFile(input_filename->value(0)); |
||||
|
} else if (input_string->count()) { |
||||
|
network.parseFromString(input_string->value(0)); |
||||
|
} |
||||
|
network.maxFlowDinic(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
typedef int VertexID; |
||||
|
typedef int Capacity; |
||||
|
typedef int Flow; |
||||
|
|
||||
|
typedef struct Arc { |
||||
|
VertexID start; |
||||
|
VertexID end; |
||||
|
Capacity capacity; |
||||
|
Capacity residual_capacity; // might not be needed |
||||
|
Flow flow; // might not be needed |
||||
|
} Arc; |
@ -0,0 +1,7 @@ |
|||||
|
list(APPEND SRCS |
||||
|
${CMAKE_CURRENT_LIST_DIR}/Arc.h |
||||
|
${CMAKE_CURRENT_LIST_DIR}/GraphParser.cpp |
||||
|
${CMAKE_CURRENT_LIST_DIR}/OptionParser.cpp |
||||
|
${CMAKE_CURRENT_LIST_DIR}/Vertex.cpp |
||||
|
${CMAKE_CURRENT_LIST_DIR}/popl.hpp |
||||
|
) |
@ -0,0 +1,76 @@ |
|||||
|
#include <algorithm>
|
||||
|
#include <fstream>
|
||||
|
#include <iostream> // only debug
|
||||
|
#include <sstream>
|
||||
|
|
||||
|
#include "GraphParser.h"
|
||||
|
#include "Vertex.h"
|
||||
|
|
||||
|
void parseGraphInformation(const std::string &line, int &num_vertices, int &num_arcs, VertexID &source, VertexID &sink) { |
||||
|
int num; |
||||
|
std::vector<int> information; |
||||
|
std::istringstream ss(line); |
||||
|
for (; ss;) { |
||||
|
if (ss >> num) { |
||||
|
information.push_back(num); |
||||
|
} else if (!ss.eof()) { |
||||
|
ss.clear(); |
||||
|
ss.ignore(1); |
||||
|
} |
||||
|
} |
||||
|
if(information.size() != 4) { |
||||
|
std::cerr << "The graph information on line 0 is not well defined:\n"; |
||||
|
std::cerr << line << std::endl; |
||||
|
throw std::runtime_error("The graph information on line 0 is not well defined."); |
||||
|
} |
||||
|
num_vertices = information.at(0); |
||||
|
num_arcs = information.at(1); |
||||
|
source = information.at(2); |
||||
|
sink = information.at(3); |
||||
|
} |
||||
|
|
||||
|
Arc parseArc(const std::string &line, const int &line_count) { |
||||
|
try { |
||||
|
int start, dest, capacity; |
||||
|
std::istringstream(line) >> start >> dest >> capacity; |
||||
|
return Arc{start, dest, capacity, capacity, 0}; // check sanity here
|
||||
|
} catch(const std::exception &e) { |
||||
|
std::cerr << "Error on line " << line_count << ":\t" << line << std::endl; |
||||
|
throw std::runtime_error("Error parsing the arc on line " + std::to_string(line_count)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
namespace parser { |
||||
|
void parseString(const std::string &graph_string, std::vector<Arc> &arc_list, std::vector<Vertex> &vertices, VertexID &source_id, VertexID &sink_id, int &num_vertices, int &num_arcs) { |
||||
|
int line_count = 0; |
||||
|
std::set<Vertex> vertex_set; |
||||
|
|
||||
|
std::stringstream stream(graph_string); |
||||
|
std::string line; |
||||
|
std::getline(stream, line); |
||||
|
parseGraphInformation(line, num_vertices, num_arcs, source_id, sink_id); |
||||
|
line_count++; |
||||
|
|
||||
|
while (std::getline(stream, line)) { |
||||
|
Arc arc = parseArc(line, line_count); |
||||
|
arc_list.push_back(arc); |
||||
|
vertex_set.insert(Vertex{arc.start}); |
||||
|
vertex_set.insert(Vertex{arc.end}); |
||||
|
line_count++; |
||||
|
} |
||||
|
|
||||
|
vertices.resize(vertex_set.size()); |
||||
|
std::copy(vertex_set.begin(), vertex_set.end(), vertices.begin()); |
||||
|
|
||||
|
for(auto &arc : arc_list) { |
||||
|
auto it = std::find_if(vertices.begin(), vertices.end(), [&arc] (const Vertex &v) { return v.getID() == arc.start; }); // check if capacity is > 0
|
||||
|
it->addOutgoingArc(arc); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void parseFile(const std::string &graph_filename, std::vector<Arc> &m_arc_list, std::vector<Vertex> &m_vertices, VertexID &source_id, VertexID &sink_id, int &m_num_vertices, int &m_num_arcs) { |
||||
|
std::ifstream input_file(graph_filename); |
||||
|
std::string content((std::istreambuf_iterator<char>(input_file)), (std::istreambuf_iterator<char>())); |
||||
|
parseString(content, m_arc_list, m_vertices, source_id, sink_id, m_num_vertices, m_num_arcs); |
||||
|
} |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <set> |
||||
|
#include <string> |
||||
|
#include <vector> |
||||
|
|
||||
|
#include "Vertex.h" |
||||
|
#include "Arc.h" |
||||
|
|
||||
|
class Vertex; |
||||
|
|
||||
|
namespace parser { |
||||
|
void parseString(const std::string &graph_string, std::vector<Arc> &m_arc_list, std::vector<Vertex> &m_vertices, VertexID &source_id, VertexID &sink_id, int &m_num_vertices, int &m_num_arcs); |
||||
|
|
||||
|
void parseFile(const std::string &graph_filename, std::vector<Arc> &m_arc_list, std::vector<Vertex> &m_vertices, VertexID &source_id, VertexID &sink_id, int &m_num_vertices, int &m_num_arcs); |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
#include <iostream>
|
||||
|
|
||||
|
#include "popl.hpp"
|
||||
|
#include "OptionParser.h"
|
||||
|
|
||||
|
namespace parser { |
||||
|
int printPoplException(const popl::invalid_option &e) { |
||||
|
std::cerr << "Invalid Option Exception: " << e.what() << "\n"; |
||||
|
std::cerr << "error: "; |
||||
|
if (e.error() == popl::invalid_option::Error::missing_argument) { |
||||
|
std::cerr << "missing_argument\n"; |
||||
|
} else if (e.error() == popl::invalid_option::Error::invalid_argument) { |
||||
|
std::cerr << "invalid_argument\n"; |
||||
|
} else if (e.error() == popl::invalid_option::Error::too_many_arguments) { |
||||
|
std::cerr << "too_many_arguments\n"; |
||||
|
} else if (e.error() == popl::invalid_option::Error::missing_option) { |
||||
|
std::cerr << "missing_option\n"; |
||||
|
} |
||||
|
|
||||
|
if (e.error() == popl::invalid_option::Error::missing_option) { |
||||
|
std::string option_name(e.option()->name(popl::OptionName::short_name, true)); |
||||
|
if (option_name.empty()) |
||||
|
option_name = e.option()->name(popl::OptionName::long_name, true); |
||||
|
std::cerr << "option: " << option_name << "\n"; |
||||
|
} |
||||
|
else { |
||||
|
std::cerr << "option: " << e.option()->name(e.what_name()) << "\n"; |
||||
|
std::cerr << "value: " << e.value() << "\n"; |
||||
|
} |
||||
|
return EXIT_FAILURE; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int checkOption(const int input_filename_count, |
||||
|
const int input_string_count) { |
||||
|
if(input_filename_count > 1) { |
||||
|
std::cerr << "You may only pass one input graph file."; |
||||
|
return INPUT_ERROR; |
||||
|
} |
||||
|
if(input_string_count > 1) { |
||||
|
std::cerr << "You may only pass one input graph string."; |
||||
|
return INPUT_ERROR; |
||||
|
} |
||||
|
if(input_filename_count > 0 && input_string_count > 0) { |
||||
|
std::cerr << "You may only pass either an input graph file or an input graph string."; |
||||
|
return INPUT_ERROR; |
||||
|
} |
||||
|
if(input_filename_count == 0 && input_string_count == 0) { |
||||
|
std::cerr << "You need to pass either and input graph file or an input graph string."; |
||||
|
return INPUT_ERROR; |
||||
|
} |
||||
|
return INPUT_OK; |
||||
|
} |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <iostream> |
||||
|
|
||||
|
#include "popl.hpp" |
||||
|
|
||||
|
#define INPUT_ERROR 1 |
||||
|
#define INPUT_OK 0 |
||||
|
|
||||
|
namespace parser { |
||||
|
int printPoplException(const popl::invalid_option &e); |
||||
|
int checkOption(const int input_filename_count, |
||||
|
const int input_string_count); |
||||
|
|
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
#include "Vertex.h"
|
||||
|
|
||||
|
Vertex::Vertex() {} |
||||
|
Vertex::Vertex(const int &id) : m_id(id) {} |
||||
|
|
||||
|
VertexID Vertex::getID() const { |
||||
|
return m_id; |
||||
|
} |
||||
|
std::vector<Arc> Vertex::getOutgoingArcs() const { |
||||
|
return m_outgoing_arcs; |
||||
|
} |
||||
|
|
||||
|
int Vertex::getLevel() const { |
||||
|
return m_level; |
||||
|
} |
||||
|
|
||||
|
bool Vertex::visited() const { |
||||
|
return m_visited; |
||||
|
} |
||||
|
|
||||
|
bool Vertex::hasDefinedLevel() const { |
||||
|
return m_level != UNDEF_LEVEL; |
||||
|
} |
||||
|
|
||||
|
void Vertex::addOutgoingArc(const Arc &arc) { |
||||
|
m_outgoing_arcs.push_back(arc); |
||||
|
} |
||||
|
|
||||
|
void Vertex::setLevel(const int &level) { |
||||
|
m_level = level; |
||||
|
} |
||||
|
|
||||
|
void Vertex::setVisited(const bool &visited) { |
||||
|
m_visited = visited; |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include "Arc.h" |
||||
|
#include "GraphParser.h" |
||||
|
|
||||
|
#define UNDEF_LEVEL -1 |
||||
|
|
||||
|
class Vertex { |
||||
|
public: |
||||
|
Vertex(); |
||||
|
Vertex(const int &id); |
||||
|
|
||||
|
VertexID getID() const; |
||||
|
std::vector<Arc> getOutgoingArcs() const; |
||||
|
int getLevel() const; |
||||
|
bool visited() const; |
||||
|
bool hasDefinedLevel() const; |
||||
|
|
||||
|
void addOutgoingArc(const Arc &arc); |
||||
|
void setLevel(const int &level); |
||||
|
void setVisited(const bool &visited = true); |
||||
|
|
||||
|
private: |
||||
|
VertexID m_id; |
||||
|
int m_level; |
||||
|
bool m_visited; |
||||
|
std::vector<Arc> m_outgoing_arcs; |
||||
|
}; |
||||
|
|
||||
|
inline bool operator<(const Vertex& lhs, const Vertex& rhs) { |
||||
|
return lhs.getID() < rhs.getID(); |
||||
|
} |
1331
util/popl.hpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue