1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

lib/graph: add path-finding with loop detection and corresponding unittest

This commit is contained in:
Daniel Krebs 2018-01-30 17:28:13 +01:00
parent ec8e9a1cd1
commit 27c67f206e
2 changed files with 114 additions and 2 deletions

View file

@ -6,6 +6,7 @@
#include <sstream>
#include <string>
#include <stdexcept>
#include <algorithm>
#include "log.hpp"
@ -168,6 +169,50 @@ public:
vertexGetEdges(VertexIdentifier vertexId) const
{ return getVertex(vertexId)->edges; }
bool getPath(VertexIdentifier fromVertexId, VertexIdentifier toVertexId,
std::list<EdgeIdentifier>& path)
{
if(fromVertexId == toVertexId) {
// arrived at the destination
return true;
} else {
auto fromVertex = getVertex(fromVertexId);
for(auto& edgeId : fromVertex->edges) {
auto edge = getEdge(edgeId);
// loop detection
bool loop = false;
for(auto& edgeIdInPath : path) {
auto edgeInPath = getEdge(edgeIdInPath);
if(edgeInPath->from == edgeId) {
loop = true;
break;
}
}
if(loop) {
logger->debug("Loop detected via edge {}", edgeId);
continue;
}
// remember the path we're investigating to detect loops
path.push_back(edgeId);
// recursive, depth-first search
if(getPath(edge->to, toVertexId, path)) {
// path found, we're done
return true;
} else {
// tear down path that didn't lead to the destination
path.pop_back();
}
}
}
return false;
}
void dump()
{
logger->info("Vertices:");

View file

@ -2,10 +2,14 @@
#include <criterion/criterion.h>
#include <villas/directed_graph.hpp>
#include <villas/log.hpp>
Test(graph, directed, .description = "DirectedGraph")
Test(graph, basic, .description = "DirectedGraph")
{
villas::graph::DirectedGraph<> g;
auto logger = loggerGetOrCreate("unittest:basic");
logger->info("Testing basic graph construction and modification");
villas::graph::DirectedGraph<> g("unittest:basic");
std::shared_ptr<villas::graph::Vertex> v1(new villas::graph::Vertex);
std::shared_ptr<villas::graph::Vertex> v2(new villas::graph::Vertex);
@ -30,3 +34,66 @@ Test(graph, directed, .description = "DirectedGraph")
cr_assert(g.getVertexCount() == 2);
cr_assert(g.vertexGetEdges(v2id).size() == 0);
}
Test(graph, path, .description = "Find path")
{
auto logger = loggerGetOrCreate("unittest:path");
logger->info("Testing path finding algorithm");
villas::graph::DirectedGraph<> g("unittest:path");
std::shared_ptr<villas::graph::Vertex> v1(new villas::graph::Vertex);
std::shared_ptr<villas::graph::Vertex> v2(new villas::graph::Vertex);
std::shared_ptr<villas::graph::Vertex> v3(new villas::graph::Vertex);
std::shared_ptr<villas::graph::Vertex> v4(new villas::graph::Vertex);
std::shared_ptr<villas::graph::Vertex> v5(new villas::graph::Vertex);
std::shared_ptr<villas::graph::Vertex> v6(new villas::graph::Vertex);
auto v1id = g.addVertex(v1);
auto v2id = g.addVertex(v2);
auto v3id = g.addVertex(v3);
auto v4id = g.addVertex(v4);
auto v5id = g.addVertex(v5);
auto v6id = g.addVertex(v6);
g.addEdge(v1id, v2id);
g.addEdge(v2id, v3id);
// create circular subgraph
g.addEdge(v4id, v5id);
g.addEdge(v5id, v4id);
g.addEdge(v5id, v6id);
g.dump();
logger->info("Find simple path via two edges");
std::list<villas::graph::EdgeIdentifier> path1;
cr_assert(g.getPath(v1id, v3id, path1));
logger->info(" Path from {} to {} via:", v1id, v3id);
for(auto& edge : path1) {
logger->info(" -> edge {}", edge);
}
logger->info("Find path between two unconnected sub-graphs");
std::list<villas::graph::EdgeIdentifier> path2;
cr_assert(not g.getPath(v1id, v4id, path2));
logger->info(" no path found -> ok");
logger->info("Find non-existing path in circular sub-graph");
std::list<villas::graph::EdgeIdentifier> path3;
cr_assert(not g.getPath(v4id, v2id, path3));
logger->info(" no path found -> ok");
logger->info("Find path in circular graph");
std::list<villas::graph::EdgeIdentifier> path4;
cr_assert(g.getPath(v4id, v6id, path4));
logger->info(" Path from {} to {} via:", v4id, v6id);
for(auto& edge : path4) {
logger->info(" -> edge {}", edge);
}
}