Skip to content
Open
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
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ target_include_directories (tinygraph PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

add_executable(tinygraph_test test.cpp)
target_link_libraries (tinygraph_test LINK_PUBLIC tinygraph)

add_executable(bellman_ford_test tests/bellman_ford_test.cpp)
target_link_libraries (bellman_ford_test LINK_PUBLIC tinygraph)
287 changes: 286 additions & 1 deletion data/graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <functions/util.h>
#include <algorithm>
#include "graph.h"
#include <variant>

namespace tinygraph {
Graph::Graph() = default;
Expand Down Expand Up @@ -66,5 +67,289 @@ namespace tinygraph {
this->str();
return std::vector<std::vector<std::string>>();
}
}

void Graph::reset_paths()
{
distances.clear();
parent.clear();
}

bool Graph::vertex_exists(const std::string& vertex)
{
for(auto& [vertex_name, vertex_ptr] : vertices)
{
if (vertex_name == vertex)
{
return true;
}
}
return false;
}


bool Graph::initialize_distances() {
number infinity;
for (auto& [vertex_name, vertex_ptr] : vertices)
{
for (auto& edge : vertex_ptr->connections)
{
if (edge->properties && edge->properties->find(path_property) != edge->properties->end())
{
std::any property = edge->properties->at(path_property);

if (property.type() == typeid(int))
{
infinity = std::numeric_limits<int>::max();
}
else if (property.type() == typeid(float))
{
infinity = std::numeric_limits<float>::max();
}
else if (property.type() == typeid(double))
{
infinity = std::numeric_limits<double>::max();
}
else return false;

for (auto& [vertex_name, vertex_ptr] : vertices)
{
distances[vertex_name] = infinity;
parent[vertex_name] = "";
}
distances[source_name] = 0;

return true;

}
else if (edge->properties && edge->properties->find(path_property) == edge->properties->end())
{
return false;
}
}
}
return false;
}

Graph::number Graph::find_value(std::any& property)
{
if (property.type() == typeid(int))
{
return std::any_cast<int>(property);
}
else if (property.type() == typeid(float))
{
return std::any_cast<float>(property);
}
else if (property.type() == typeid(double))
{
return std::any_cast<double>(property);
}

else return std::numeric_limits<int>::min();
}

bool Graph::bellman_ford(const std::string& the_source_name, const std::string& sorting_property)
{
if (sorting_property.empty() || the_source_name.empty()) return false;
path_property = sorting_property;
source_name = the_source_name;
if (!vertex_exists(the_source_name))
{
reset_paths();
return false;
}

if (!initialize_distances())
{
reset_paths();
return false;
}

for (int i=0; i<vertices.size()-1; i++)
{
for (auto& [vertex_name, vertex_ptr] : vertices)
{
for (auto& edge : vertex_ptr->connections)
{
if (edge->properties && edge->properties->find(sorting_property) != edge->properties->end())
{
std::any property = edge->properties->at(path_property);

number weight = find_value(property);

if (typeid(weight) == typeid(int) && std::get<int>(weight) == std::numeric_limits<int>::min())
{
reset_paths();
return false;
}

auto& ref_vertex_name = vertex_name;

std::visit(
[this, &ref_vertex_name, &edge](auto& distance_from, auto& distance_to, auto& weight) {

using type_used = std::common_type_t<decltype(distance_from), decltype(distance_to), decltype(weight)>;
if (distance_from != std::numeric_limits<type_used>::max() && distance_to > distance_from + weight)
{
this->distances[edge->to->name] = distance_from + weight;
this->parent[edge->to->name] = ref_vertex_name;
}

},
distances[vertex_name],
distances[edge->to->name],
weight
);
}


else if (edge->properties && edge->properties->find(sorting_property) == edge->properties->end())
{
reset_paths();
return false;
}
}
}
}

for (auto& [vertex_name, vertex_ptr] : vertices)
{
for (auto& edge : vertex_ptr->connections)
{
if (edge->properties && edge->properties->find(sorting_property) != edge->properties->end())
{
std::any property = edge->properties->at(path_property);

number weight = find_value(property);

if (typeid(weight) == typeid(int) && std::get<int>(weight) == std::numeric_limits<int>::min())
{
reset_paths();
return false;
}

bool returning = true;

std::visit(
[this, &returning](auto& distance_from, auto& distance_to, auto& weight) {
using type_used = std::common_type_t<decltype(distance_from), decltype(distance_to), decltype(weight)>;
if (distance_from != std::numeric_limits<type_used>::max() && distance_to > distance_from + weight)
{
this->negative_cycle = negative;
returning = false;
}

},
distances[vertex_name],
distances[edge->to->name],
weight
);

if (!returning)
{
reset_paths();
return false;
}
}
}
}
negative_cycle = non_negative;
return true;
}


std::vector<std::string> Graph::find_shortest_path(const std::string& destination)
{
std::vector<std::string> shortest_path;

if (!vertex_exists(destination))
{
return shortest_path;
}

std::string current = destination;


while (current != source_name)
{
if (current.empty())
{
shortest_path.clear();
return shortest_path;
}
shortest_path.push_back(current);
current = parent[current];
}

shortest_path.push_back(current);

std::reverse(shortest_path.begin(), shortest_path.end());

return shortest_path;
}

void Graph::dfs(const std::string& current, const std::string& destination, std::map<std::string, vector<std::string>>& adj, std::map<std::string, bool>& visited, std::vector<std::string>& path, bool& found)
{
visited[current] = true;

path.push_back(current);

if (current == destination)
{
found = true;
return;
}

for (std::string testing : adj[current])
{
if (!visited[testing] && !found)
{
dfs(testing, destination, adj, visited, path, found);
}
}
if (!found) path.pop_back();
}

bool Graph::dfsSetup(const std::string& source, const std::string& destination)
{
if (vertices.find(source) == vertices.end() || vertices.find(destination) == vertices.end()) return false;

std::map<std::string, vector<std::string>> adj;
std::map<std::string, bool> visited;

std::vector<std::string> path;

for (auto& [vertex_name, vertex_ptr] : vertices)
{
visited[vertex_name] = false;
}



for (auto& [vertex_name, vertex_ptr] : vertices)
{
for (auto& edge : vertex_ptr->connections)
{
if (undirected)
{
adj[vertex_name].push_back(edge->to->name);
adj[edge->to->name].push_back(vertex_name);
}
else
{
adj[vertex_name].push_back(edge->to->name);
}
}
}

bool found = false;

dfs(source, destination, adj, visited, path, found);

if (!found) path.clear();

return found;


}
}
32 changes: 32 additions & 0 deletions data/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "types.h"
#include <vector>
#include <variant>

namespace tinygraph {
class Graph {
Expand All @@ -27,6 +28,37 @@ namespace tinygraph {
std::vector<std::vector<std::string>> connected_components();

std::string str();

using number = std::variant<int, float, double>; // more types can be added here

std::map<std::string, number> distances;

std::map<std::string, std::string> parent;

std::string path_property;

bool bellman_ford(const std::string& the_source_name, const std::string& sorting_property);

bool vertex_exists(const std::string& vertex);

void reset_paths();

std::string source_name;

std::vector<std::string> find_shortest_path(const std::string& destination);

enum neg_cycle_state { unknown, negative, non_negative };

neg_cycle_state negative_cycle = unknown;

bool initialize_distances();

number find_value(std::any& property);

void dfs(const std::string& current, const std::string& destination, std::map<std::string, vector<std::string>>& adj, std::map<std::string, bool>& visited, std::vector<std::string>& path);

bool dfsSetup(const std::string& source, const std::string& destination);

};
}

Expand Down
Loading