Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion detail/add_edges.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void add_edge(const std::vector<node>& new_value, const node& key, const std::st
auto g_it = graph.find(key);

if (g_it == graph.end()) {
std::cout << "Key doesnt exist" << std::endl;
std::cout << "Key doesnt exist" << "\n";
return;
}

Expand Down
2 changes: 1 addition & 1 deletion detail/add_edges_weighted.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void add_edge(const std::vector<std::pair<node, weights>>& new_value, const node
auto g_it = graph.find(key);

if (g_it == graph.end()) {
std::cout << "Key doesnt exist" << std::endl;
std::cout << "Key doesnt exist" << "\n";
return;
}

Expand Down
2 changes: 1 addition & 1 deletion detail/delete_nodes.tpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace graphlib {

void delete_instances(const std::string& node_to_delete, const std::string& input_file) {
inline void delete_instances(const std::string& node_to_delete, const std::string& input_file) {
std::vector<std::string> lines;
std::string line;
std::regex nodetodeletepattern("^Node " + node_to_delete + "\\b");
Expand Down
2 changes: 1 addition & 1 deletion detail/delete_nodes_weighted.tpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace graphlib {

void delete_instances_weighted(const std::string& node_to_delete, const std::string& input_file) {
inline void delete_instances_weighted(const std::string& node_to_delete, const std::string& input_file) {
std::vector<std::string> lines;
std::string line;
std::regex nodetodeletepattern("^Node " + node_to_delete + "\\b");
Expand Down
16 changes: 16 additions & 0 deletions detail/get_neighbors.tpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace graphlib {

template<typename node>

std::vector<node> get_neighbors(const node& key, std::unordered_map<node, std::vector<node>>& graph) {

auto g_it = graph.find(key);

if (g_it == graph.end()) {
std::cout << "Key doesnt exist" << "\n";
return {};
}

return g_it->second;
}
}
22 changes: 22 additions & 0 deletions detail/get_neighbors_weighted.tpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace graphlib {

template<typename node, typename weights>

std::vector<node> get_neighbors(const node& key, std::unordered_map<node, std::vector<std::pair<node, weights>>>& graph) {

auto g_it = graph.find(key);

if (g_it == graph.end()) {
std::cout << "Key doesnt exist" << "\n";
return {};
}

std::vector<node> neighbors;

for (const auto& edge_pair : g_it->second) {
neighbors.push_back(edge_pair.first);
}

return neighbors;
}
}
3 changes: 3 additions & 0 deletions detail/print_version.tpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
inline void graphlib_version() {
std::cout << "Version 3.1" << '\n';
}
14 changes: 14 additions & 0 deletions include/graphlib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ template<typename node>
void delete_instances(const std::string& node_to_delete, const std::string& input_file);

void print_graph(const std::string& filename);
void graphlib_version();

template<typename node, typename weights>
requires Number<weights>
Expand All @@ -55,15 +56,27 @@ template<typename node, typename weights>
requires Number<weights>
std::unordered_map<node, std::vector<std::pair<node, weights>>> parse_weighted(const std::string& input_file);

template<typename node>
std::vector<node> get_neighbors(const node& key, std::unordered_map<node, std::vector<node>>& graph);

template<typename node, typename weights>
std::vector<node> get_neighbors(const node& key, std::unordered_map<node, std::vector<std::pair<node, weights>>>& graph);

template<typename node>
std::vector<node> dfs_algorithm(const node& starting_value, const std::string& input_file);
template<typename node>
std::vector<node> bfs_algorithm(const node& starting_node, const std::string& input_file);
template<typename node, typename weights>

requires Number<weights>
std::vector<node> dijkstras_algorithm(const node starting_node, const std::string& input_file);
}

#include "../detail/txt_to_un_map.tpp"
#include "../detail/txt_to_un_map_weighted.tpp"

#include "../detail/get_neighbors.tpp"
#include "../detail/get_neighbors_weighted.tpp"
#include "../detail/add_nodes.tpp"
#include "../detail/add_nodes_weighted.tpp"
#include "../detail/create_graph.tpp"
Expand All @@ -77,5 +90,6 @@ std::vector<node> bfs_algorithm(const node& starting_node, const std::string& in
#include "../detail/bfs.tpp"
#include "../detail/dijkstra.tpp"
#include "../detail/print_graph.tpp"
#include "../detail/print_version.tpp"

#endif
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ project(graphlib_tests LANGUAGES CXX)

set(TEST_SOURCES
"test_core.cpp"
"test_d_and_g_n.cpp"
)

add_executable(run_tests ${TEST_SOURCES})
Expand Down
8 changes: 8 additions & 0 deletions tests/test_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

using namespace std;

// forward declaration for tests in test_d_and_g_n.cpp (merged runner)
extern int run_d_and_g_n_tests();

namespace {

std::atomic<uint64_t> g_checks_done{0};
Expand Down Expand Up @@ -410,6 +413,11 @@ int main() {
<< " rss_mb=" << (get_rss_bytes() / 1024 / 1024) << std::endl;

std::cout << "Stress tests completed successfully." << std::endl;

// run additional tests from tests/test_d_and_g_n.cpp
int rc = run_d_and_g_n_tests();
if (rc != 0) return rc;

return 0;
} catch (const std::exception& ex) {
std::cerr << ex.what() << std::endl;
Expand Down
153 changes: 153 additions & 0 deletions tests/test_d_and_g_n.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#include <bits/stdc++.h>

using namespace std;

#include "graphlib.hpp"

static inline string unique_temp_path_local(const string& name) {
const auto now = chrono::steady_clock::now().time_since_epoch().count();
static atomic<uint64_t> counter{0};
const auto id = counter.fetch_add(1);
return "/tmp/graphlib_" + name + "_" + to_string(now) + "_" + to_string(id) + ".txt";
}

template<typename V>
bool same_vector_contents(const vector<V>& actual, const vector<V>& expected) {
if (actual.size() != expected.size()) return false;
vector<V> a = actual;
vector<V> e = expected;
sort(a.begin(), a.end());
sort(e.begin(), e.end());
return a == e;
}

// local Dijkstra implemented the same way as graphlib::dijkstras_algorithm
vector<int> local_dijkstra(const unordered_map<int, vector<pair<int,int>>>& graph, int start) {
const long long INF = (1LL<<60);
unordered_map<int,long long> dist;
for (const auto &kv : graph) dist[kv.first] = INF;
if (dist.find(start) == dist.end()) dist[start] = INF;

using Pair = pair<long long,int>;
priority_queue<Pair, vector<Pair>, greater<Pair>> q;
dist[start] = 0;
q.push({0, start});

vector<int> order;
while (!q.empty()) {
auto [d, u] = q.top(); q.pop();
auto it = dist.find(u);
if (it != dist.end() && d > it->second) continue;
order.push_back(u);
auto git = graph.find(u);
if (git == graph.end()) continue;
for (const auto &p : git->second) {
int v = p.first; int w = p.second;
long long nd = d + w;
auto vt = dist.find(v);
if (vt == dist.end() || nd < vt->second) {
dist[v] = nd;
q.push({nd, v});
}
}
}
return order;
}

int run_d_and_g_n_tests() {
try {
std::mt19937 rng(123456);
std::uniform_int_distribution<int> nodes_dist(0, 300);
std::uniform_int_distribution<int> deg_dist(0, 12);
std::uniform_int_distribution<int> w_dist(1, 200);

const int ITER = 200;

for (int it = 0; it < ITER; ++it) {
int N = max(0, nodes_dist(rng));

// unweighted graph
unordered_map<int, vector<int>> ug;
ug.reserve(N);
for (int i = 0; i < N; ++i) {
int deg = deg_dist(rng);
vector<int> adj;
adj.reserve(deg);
for (int e = 0; e < deg; ++e) adj.push_back(rng() % (N + 1));
ug[i] = adj;
}

if (!ug.empty()) {
// pick random existing key and check get_neighbors
int pick_idx = rng() % ug.size();
auto itg = ug.begin(); advance(itg, pick_idx);
int key = itg->first;
auto res = graphlib::get_neighbors<int>(key, ug);
if (!same_vector_contents(res, ug[key])) {
cerr << "get_neighbors (unweighted) mismatch on iteration " << it << "\n";
return 2;
}
}

// weighted graph for dijkstra and weighted get_neighbors
unordered_map<int, vector<pair<int,int>>> wg;
wg.reserve(N);
for (int i = 0; i < N; ++i) {
int deg = deg_dist(rng);
vector<pair<int,int>> adj;
adj.reserve(deg);
for (int e = 0; e < deg; ++e) adj.emplace_back(rng() % (N + 1), w_dist(rng));
wg[i] = adj;
}

// Test weighted get_neighbors: should return neighbor node ids (first)
if (!wg.empty()) {
int pick_idx = rng() % wg.size();
auto itw = wg.begin(); advance(itw, pick_idx);
int key = itw->first;
auto got = graphlib::get_neighbors<int,int>(key, wg);
vector<int> expected;
for (const auto &p : wg[key]) expected.push_back(p.first);
if (!same_vector_contents(got, expected)) {
cerr << "get_neighbors (weighted) returned unexpected values on iteration " << it << "\n";
cerr << "expected first few: ";
for (size_t i=0;i<min<size_t>(expected.size(),5);++i) cerr<<expected[i]<<" "; cerr<<"\n";
cerr << "got first few: ";
for (size_t i=0;i<min<size_t>(got.size(),5);++i) cerr<<got[i]<<" "; cerr<<"\n";
return 3;
}
}

// Dijkstra: write to file, call library dijkstra and compare order with local implementation
const string file = unique_temp_path_local("dijk");
graphlib::create_graph<int,int>(wg, file);

if (!wg.empty()) {
int pick_idx = rng() % wg.size();
auto itw = wg.begin(); advance(itw, pick_idx);
int start = itw->first;

auto lib_order = graphlib::dijkstras_algorithm<int,int>(start, file);
auto local_order = local_dijkstra(wg, start);

if (lib_order != local_order) {
cerr << "dijkstra ordering mismatch on iteration " << it << "\n";
cerr << "start=" << start << " lib_order_size=" << lib_order.size() << " local_order_size=" << local_order.size() << "\n";
cerr << "lib first 10: "; for (size_t i=0;i<min<size_t>(lib_order.size(),10);++i) cerr<<lib_order[i]<<" "; cerr<<"\n";
cerr << "loc first 10: "; for (size_t i=0;i<min<size_t>(local_order.size(),10);++i) cerr<<local_order[i]<<" "; cerr<<"\n";
remove(file.c_str());
return 4;
}
}

remove(file.c_str());
}

cout << "get_neighbors + dijkstra stress test passed (" << ITER << " iterations)" << endl;
return 0;
} catch (const exception &ex) {
cerr << "Exception: " << ex.what() << endl;
return 1;
}
}

Loading