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