Commit cd3cb4cd authored by Stian Jakobsen's avatar Stian Jakobsen
Browse files

Merge branch 'week2' into 'master'

Merge Week2

See merge request sja044/dte-3603_template_source_base!9
parents a5e59c6c c3b5808e
......@@ -56,11 +56,11 @@ target_compile_definitions(Boost::graph
add_subdirectory(predef_shared)
# Include internal library subfolders
add_subdirectory(week2)
add_subdirectory(day1_2_sort)
add_subdirectory(day3_string_match)
add_subdirectory(day4_graph_traversal)
add_subdirectory(day5_graph_path_finding)
add_subdirectory(week2_zombie)
###########################################
# Qt creator dummy target
......
1
1
S T
\ No newline at end of file
2
3 3
S 1,2 2 2
S 1,3 1 2
1,3 1,2 2 1
1,2 2,1 2 1
1,3 2,2 3 3
2,1 T 2 2
2,2 T 2 2
\ No newline at end of file
2
1 1
S U 3 1
S X 2 1
X U 3 1
X Y 3 1
U V 2 1
V X 1 1
V T 3 1
Y T 2 1
\ No newline at end of file
......@@ -54,9 +54,9 @@ namespace dte3603::predef::concepts::graph
};
template <typename Graph_T>
concept BidirectionalGraph = Graph<Graph_T>and
std::same_as<typename Graph_T::directed_selector, boost::bidirectionalS>;
concept BidirectionalGraph
= Graph<Graph_T> and std::same_as<typename Graph_T::directed_selector,
boost::bidirectionalS>;
} // namespace dte3603::predef::concepts::graph
......
#ifndef DTE3603_PREDEF_TESTING_WEEK2_MAX_FLOW_FIXTURES_H
#define DTE3603_PREDEF_TESTING_WEEK2_MAX_FLOW_FIXTURES_H
#include "max_flow_testing_gold.h"
// gtest
#include <gtest/gtest.h>
// Inspired/based on the supplied week 1 testing fixtures and adapted for flow
// algorithms
namespace dte3603::predef::testing::week2_zombie::fixtures
{
template <typename GoldGraph_T>
struct GoldGraphTestF : ::testing::Test {
using GoldGraph = GoldGraph_T;
using ::testing::Test::Test;
~GoldGraphTestF() override {}
std::unique_ptr<GoldGraph> gold;
void SetUp() final { gold = std::make_unique<GoldGraph>(); }
void TearDown() final { gold.release(); }
};
using EmptyGraphF = GoldGraphTestF<gold::EmptyGraph>;
using FirstExampleGraphF = GoldGraphTestF<gold::FirstExampleGraph>;
using MiTExampleGraphF = GoldGraphTestF<gold::MiTGraphExample>;
// // Special purpose fixtures
// using SingleNodeDAGF = GoldGraphTestF<gold::SingleNodeDAG>;
// using TreeDAGF = GoldGraphTestF<gold::TreeDAG>;
// // Brute force test fixtures
// using DAGOneF = GoldGraphTestF<gold::DAGOne>;
// using DAGTwoF = GoldGraphTestF<gold::DAGTwo>;
// using DAGThreeF = GoldGraphTestF<gold::DAGThree>;
} // namespace dte3603::predef::testing::week2_zombie::fixtures
#endif // DTE3603_PREDEF_TESTING_WEEK2_MAX_FLOW_FIXTURES_H
#ifndef DTE3603_PREDEF_TESTING_WEEK2_MAX_FLOW_GOLD_H
#define DTE3603_PREDEF_TESTING_WEEK2_MAX_FLOW_GOLD_H
// boost
#include <boost/graph/adjacency_list.hpp>
// gtest
#include <gtest/gtest.h>
// stl
#include <concepts>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <random>
#include <filesystem>
#include <iostream>
#include <fstream>
// Inspired/based on the supplied week 1 testing gold and adapted for flow
// algorithms
namespace dte3603::predef::testing::week2_zombie
{
namespace detail
{
namespace types
{
namespace properties
{
struct NodeProperties {
std::string name;
};
struct EdgeProperties {
double flow;
double cost;
double flow_capacity;
};
using GraphProperties = boost::no_property;
} // namespace properties
using BidirectionalGraph
= boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
properties::NodeProperties,
properties::EdgeProperties,
properties::GraphProperties>;
} // namespace types
template <typename GraphType_T>
struct GoldGraphTemplate {
using Graph = GraphType_T;
using VP = typename Graph::vertex_property_type;
using EP = typename Graph::edge_property_type;
using VD = typename Graph::vertex_descriptor;
using ED = typename Graph::edge_descriptor;
using VDVector = std::vector<VD>;
using VDVecVector = std::vector<VDVector>;
GoldGraphTemplate() = default;
virtual ~GoldGraphTemplate() = default;
Graph& graph() { return m_graph; }
Graph m_graph;
};
} // namespace detail
namespace gold
{
class EmptyGraph
: public detail::GoldGraphTemplate<detail::types::BidirectionalGraph> {
// Getting our current path and gonig for the flow_graphs folder that will
// hopefully be present *may* require platform-specific code for paths,
// since Windows can be funky.
std::string graph_src_path
= std::filesystem::current_path().append("flow_graphs/empty_graph.txt");
// Using ifstream rather than fstream since we only need to read the file
std::ifstream input_reader;
// number of floors and nodes as read from the file "header"
int n_floors;
std::vector<int> n_nodes;
// Vertex descriptors for the source and sink to be read from file
VD source, sink;
public:
EmptyGraph()
{
input_reader.open(graph_src_path);
input_reader >> n_floors;
int v;
// May need to implement some safety checks at some point
for (auto i = 0; i < n_floors; i++) {
input_reader >> v;
n_nodes.push_back(v);
}
// Better while that had to be exchanged for peek with eof to allow for
// string node names
// TODO: Replace with better alternative
// double x;
// while (input_reader >> x) {
// int cost, capacity, n1, n2;
// input_reader >> node_one >> node_two >> cost >> capacity;
// }
// While that runs as long as the next line isn't end of line (-1), not
// ideal
while (input_reader.peek() != EOF) {
std::string v1, v2;
double cost, flow_cap;
input_reader >> v1 >> v2 >> flow_cap >> cost;
source = boost::add_vertex(VP{.name = v1}, m_graph);
sink = boost::add_vertex(VP{.name = v2}, m_graph);
boost::add_edge(
source, sink,
EP{.flow = 0., .cost = cost, .flow_capacity = flow_cap}, m_graph);
}
}
~EmptyGraph() override {}
VD& Source() { return source; }
VD& Sink() { return sink; }
// Empty graph so max flow is 0, and there is no shortest path (since
// there is no path)
auto maxFlowGold() const { return 0.; }
};
// Initial graph example given by professor in task description
class FirstExampleGraph
: public detail::GoldGraphTemplate<detail::types::BidirectionalGraph> {
// Getting our current path and gonig for the flow_graphs folder that will
// hopefully be present *may* require platform-specific code for paths,
// since Windows can be funky.
std::string graph_src_path = std::filesystem::current_path().append(
"flow_graphs/initial_example_graph.txt");
// Using ifstream rather than fstream since we only need to read the file
std::ifstream input_reader;
// number of floors and nodes as read from the file "header"
int n_floors;
std::vector<int> n_nodes;
// map of vertices in graph as read from file
std::unordered_map<std::string, VD> v_map;
// Vertex descriptors for the source and sink to be read from file
VD source, sink;
public:
FirstExampleGraph()
{
input_reader.open(graph_src_path);
input_reader >> n_floors;
// May need to implement some safety checks at some point
int v;
for (auto i = 0; i < n_floors; i++) {
input_reader >> v;
}
// Finding and adding all edges from file
while (input_reader.peek() != EOF) {
std::string v1, v2;
double cost, flow_cap;
input_reader >> v1 >> v2 >> flow_cap >> cost;
insertInMap(v1, "S", source);
insertInMap(v2, "T", sink);
boost::add_edge(
v_map.at(v1), v_map.at(v2),
EP{.flow = 0., .cost = cost, .flow_capacity = flow_cap}, m_graph);
}
}
// Would ideally be a universal helper method for all test classes.
// Could not work around an issue to solve this, ideally done in the
// future.
void insertInMap(std::string& v, std::string target, VD& v_target)
{
if (!v_map.contains(v)) {
if (v == target) {
v_target = boost::add_vertex(VP{.name = v}, m_graph);
v_map.insert(std::make_pair(v, v_target));
}
else {
v_map.insert(
std::make_pair(v, boost::add_vertex(VP{.name = v}, m_graph)));
}
}
}
~FirstExampleGraph() override {}
VD& Source() { return source; }
VD& Sink() { return sink; }
auto maxFlowGold() const { return 3.; }
};
// MiT Graph example from MiT lecture
class MiTGraphExample
: public detail::GoldGraphTemplate<detail::types::BidirectionalGraph> {
// Getting our current path and gonig for the flow_graphs folder that will
// hopefully be present *may* require platform-specific code for paths,
// since Windows can be funky.
std::string graph_src_path = std::filesystem::current_path().append(
"flow_graphs/mit_graph_example.txt");
// Using ifstream rather than fstream since we only need to read the file
std::ifstream input_reader;
// number of floors and nodes as read from the file "header"
std::vector<int> n_nodes;
int n_floors;
// map of vertices in graph as read from file
std::unordered_map<std::string, VD> v_map;
// Vertex descriptors for the source and sink to be read from file
VD source, sink;
public:
MiTGraphExample()
{
input_reader.open(graph_src_path);
input_reader >> n_floors;
int v;
for (auto i = 0; i < n_floors; i++) {
input_reader >> v;
}
while (input_reader.peek() != EOF) {
std::string v1, v2;
double cost, flow_cap;
input_reader >> v1 >> v2 >> flow_cap >> cost;
insertInMap(v1, "S", source);
insertInMap(v2, "T", sink);
boost::add_edge(
v_map.at(v1), v_map.at(v2),
EP{.flow = 0., .cost = cost, .flow_capacity = flow_cap}, m_graph);
}
}
// Would ideally be a universal helper method for all test classes.
// Could not work around an issue to solve this in the time remaining,
// ideally done in the future.
void insertInMap(std::string& v, std::string target, VD& v_target)
{
if (!v_map.contains(v)) {
if (v == target) {
v_target = boost::add_vertex(VP{.name = v}, m_graph);
v_map.insert(std::make_pair(v, v_target));
}
else {
v_map.insert(
std::make_pair(v, boost::add_vertex(VP{.name = v}, m_graph)));
}
}
}
~MiTGraphExample() override {}
VD& Source() { return source; }
VD& Sink() { return sink; }
auto maxFlowGold() const { return 4.; }
};
} // namespace gold
} // namespace dte3603::predef::testing::week2_zombie
#endif // DTE3603_PREDEF_TESTING_GRAPH_GOLD_H
#ifndef DTE3603_PREDEF_TESTING_WEEK2_MIN_COST_FLOW_FIXTURES_H
#define DTE3603_PREDEF_TESTING_WEEK2_MIN_COST_FLOW_FIXTURES_H
#include "min_cost_flow_testing_gold.h"
// gtest
#include <gtest/gtest.h>
// Inspired/based on the supplied week 1 testing fixtures and adapted for flow
// algorithms
namespace dte3603::predef::testing::week2_zombie::fixtures
{
template <typename GoldGraph_T>
struct GoldGraphTestF : ::testing::Test {
using GoldGraph = GoldGraph_T;
using ::testing::Test::Test;
~GoldGraphTestF() override {}
std::unique_ptr<GoldGraph> gold;
void SetUp() final { gold = std::make_unique<GoldGraph>(); }
void TearDown() final { gold.release(); }
};
using EmptyGraphF = GoldGraphTestF<gold::EmptyGraph>;
using FirstExampleGraphF = GoldGraphTestF<gold::FirstExampleGraph>;
using MiTExampleGraphF = GoldGraphTestF<gold::MiTGraphExample>;
// // Special purpose fixtures
// using SingleNodeDAGF = GoldGraphTestF<gold::SingleNodeDAG>;
// using TreeDAGF = GoldGraphTestF<gold::TreeDAG>;
// // Brute force test fixtures
// using DAGOneF = GoldGraphTestF<gold::DAGOne>;
// using DAGTwoF = GoldGraphTestF<gold::DAGTwo>;
// using DAGThreeF = GoldGraphTestF<gold::DAGThree>;
} // namespace dte3603::predef::testing::week2_zombie::fixtures
#endif // DTE3603_PREDEF_TESTING_WEEK2_MIN_COST_FLOW_FIXTURES_H
#ifndef DTE3603_PREDEF_TESTING_WEEK2_MIN_COST_FLOW_GOLD_H
#define DTE3603_PREDEF_TESTING_WEEK2_MIN_COST_FLOW_GOLD_H
// boost
#include <boost/graph/adjacency_list.hpp>
// gtest
#include <gtest/gtest.h>
// stl
#include <concepts>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <random>
#include <filesystem>
#include <iostream>
#include <fstream>
// Inspired/based on the supplied week 1 testing gold and adapted for flow
// algorithms
namespace dte3603::predef::testing::week2_zombie
{
namespace detail
{
namespace types
{
namespace properties
{
struct NodeProperties {
std::string name;
};
struct EdgeProperties {
double flow;
double cost;
double flow_capacity;
};
using GraphProperties = boost::no_property;
} // namespace properties
using BidirectionalGraph
= boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
properties::NodeProperties,
properties::EdgeProperties,
properties::GraphProperties>;
} // namespace types
template <typename GraphType_T>
struct GoldGraphTemplate {
using Graph = GraphType_T;
using VP = typename Graph::vertex_property_type;
using EP = typename Graph::edge_property_type;
using VD = typename Graph::vertex_descriptor;
using ED = typename Graph::edge_descriptor;
using VDVector = std::vector<VD>;
using VDVecVector = std::vector<VDVector>;
GoldGraphTemplate() = default;
virtual ~GoldGraphTemplate() = default;
Graph& graph() { return m_graph; }
Graph m_graph;
};
} // namespace detail
namespace gold
{
class EmptyGraph
: public detail::GoldGraphTemplate<detail::types::BidirectionalGraph> {
// Getting our current path and gonig for the flow_graphs folder that will
// hopefully be present *may* require platform-specific code for paths,
// since Windows can be funky.
std::string graph_src_path
= std::filesystem::current_path().append("flow_graphs/empty_graph.txt");
// Using ifstream rather than fstream since we only need to read the file
std::ifstream input_reader;
// number of floors and nodes as read from the file "header"
int n_floors;
std::vector<int> n_nodes;
// Vertex descriptors for the source and sink to be read from file
VD source, sink;
public:
EmptyGraph()
{
input_reader.open(graph_src_path);
input_reader >> n_floors;
int v;
// May need to implement some safety checks at some point
for (auto i = 0; i < n_floors; i++) {
input_reader >> v;
n_nodes.push_back(v);
}
// Better while that had to be exchanged for peek with eof to allow for
// string node names
// TODO: Replace with better alternative
// double x;
// while (input_reader >> x) {
// int cost, capacity, n1, n2;
// input_reader >> node_one >> node_two >> cost >> capacity;
// }
// While that runs as long as the next line isn't end of line (-1), not
// ideal
while (input_reader.peek() != EOF) {
std::string v1, v2;
double cost, flow_cap;
input_reader >> v1 >> v2 >> flow_cap >> cost;
source = boost::add_vertex(VP{.name = v1}, m_graph);
sink = boost::add_vertex(VP{.name = v2}, m_graph);
boost::add_edge(
source, sink,
EP{.flow = 0., .cost = cost, .flow_capacity = flow_cap}, m_graph);
}
}
~EmptyGraph() override {}
VD& Source() { return source; }
VD& Sink() { return sink; }
VDVecVector bellmanFordGold() const { return {}; }
};
// Initial graph example given by professor in task description
class FirstExampleGraph
: public detail::GoldGraphTemplate<detail::types::BidirectionalGraph> {
// Getting our current path and gonig for the flow_graphs folder that will
// hopefully be present *may* require platform-specific code for paths,
// since Windows can be funky.
std::string graph_src_path = std::filesystem::current_path().append(
"flow_graphs/initial_example_graph.txt");
// Using ifstream rather than fstream since we only need to read the file