Skip to content

Commit

Permalink
talipot-core/Graph: Add extra methods to perform DFS traversals (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
anlambert committed Dec 12, 2024
1 parent ee272f8 commit e2b1400
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 39 deletions.
14 changes: 12 additions & 2 deletions library/talipot-core/include/talipot/Graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,16 @@ class TLP_SCOPE Graph : public Observable {
* @param directed if true only follow output edges, follow all edges otherwise
* @return A vector of graph nodes in the DFS order.
*/
virtual std::vector<node> dfs(const node root = node(), bool directed = false) const = 0;
virtual std::vector<node> dfs(const node root, bool directed = false) const = 0;
virtual std::vector<node> dfs(bool directed = false) const = 0;

virtual void dfs(node root, const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false) const = 0;

virtual void dfs(const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false) const = 0;

/**
* @brief Gets an iterator performing a depth-first search on the graph.
Expand All @@ -975,7 +984,8 @@ class TLP_SCOPE Graph : public Observable {
* @param directed if true only follow output edges, follow all edges otherwise
* @return A vector of graph edges in the DFS order.
*/
virtual std::vector<edge> dfsEdges(const node root = node(), bool directed = false) const = 0;
virtual std::vector<edge> dfsEdges(const node root, bool directed = false) const = 0;
virtual std::vector<edge> dfsEdges(bool directed = false) const = 0;

/**
* @brief Gets the underlying graph of a meta node.
Expand Down
14 changes: 11 additions & 3 deletions library/talipot-core/include/talipot/GraphAbstract.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (C) 2019-2023 The Talipot developers
* Copyright (C) 2019-2024 The Talipot developers
*
* Talipot is a fork of Tulip, created by David Auber
* and the Tulip development Team from LaBRI, University of Bordeaux
Expand Down Expand Up @@ -108,9 +108,17 @@ class TLP_SCOPE GraphAbstract : public Graph {
std::string getName() const override;

std::vector<node> bfs(const node root = node(), bool directed = false) const override;
std::vector<node> dfs(const node root = node(), bool directed = false) const override;
std::vector<node> dfs(const node root, bool directed = false) const override;
std::vector<node> dfs(bool directed = false) const override;
void dfs(node root, const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false) const override;
void dfs(const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false) const override;
std::vector<edge> bfsEdges(const node root = node(), bool directed = false) const override;
std::vector<edge> dfsEdges(const node root = node(), bool directed = false) const override;
std::vector<edge> dfsEdges(const node root, bool directed = false) const override;
std::vector<edge> dfsEdges(bool directed = false) const override;

protected:
DataSet &getNonConstAttributes() override {
Expand Down
14 changes: 11 additions & 3 deletions library/talipot-core/include/talipot/GraphDecorator.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (C) 2019-2023 The Talipot developers
* Copyright (C) 2019-2024 The Talipot developers
*
* Talipot is a fork of Tulip, created by David Auber
* and the Tulip development Team from LaBRI, University of Bordeaux
Expand Down Expand Up @@ -111,9 +111,17 @@ class TLP_SCOPE GraphDecorator : public Graph {
Iterator<node> *getOutNodes(const node n) const override;
Iterator<node> *getInOutNodes(const node n) const override;
std::vector<node> bfs(const node root = node(), bool directed = false) const override;
std::vector<node> dfs(const node root = node(), bool directed = false) const override;
std::vector<node> dfs(const node root, bool directed = false) const override;
std::vector<node> dfs(bool directed = false) const override;
void dfs(node root, const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false) const override;
void dfs(const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false) const override;
std::vector<edge> bfsEdges(const node root = node(), bool directed = false) const override;
std::vector<edge> dfsEdges(const node root = node(), bool directed = false) const override;
std::vector<edge> dfsEdges(const node root, bool directed = false) const override;
std::vector<edge> dfsEdges(bool directed = false) const override;
const std::vector<edge> &edges() const override;
uint edgePos(const edge) const override;
Iterator<edge> *getEdges() const override;
Expand Down
10 changes: 10 additions & 0 deletions library/talipot-core/include/talipot/GraphTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ TLP_SCOPE std::vector<edge> bfsEdges(const Graph *graph, bool directed = false);
*/
TLP_SCOPE std::vector<node> dfs(const Graph *graph, node root, bool directed = false);

TLP_SCOPE void dfs(const Graph *graph, node root,
const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false);

/**
* @brief Performs a depth-first search on a graph.
* @param graph The graph to traverse with a DFS.
Expand All @@ -188,6 +193,11 @@ TLP_SCOPE std::vector<edge> dfsEdges(const Graph *graph, node root, bool directe
*/
TLP_SCOPE std::vector<node> dfs(const Graph *graph, bool directed = false);

TLP_SCOPE void dfs(const Graph *graph,
const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed = false);

/**
* @brief Performs a cumulative depth-first search on every node of a graph.
* @param graph The graph to traverse with a DFS.
Expand Down
22 changes: 21 additions & 1 deletion library/talipot-core/src/GraphAbstract.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (C) 2019-2023 The Talipot developers
* Copyright (C) 2019-2024 The Talipot developers
*
* Talipot is a fork of Tulip, created by David Auber
* and the Tulip development Team from LaBRI, University of Bordeaux
Expand Down Expand Up @@ -499,10 +499,30 @@ std::vector<node> GraphAbstract::dfs(const node root, bool directed) const {
return tlp::dfs(this, root, directed);
}

std::vector<node> GraphAbstract::dfs(bool directed) const {
return tlp::dfs(this, directed);
}

std::vector<edge> GraphAbstract::bfsEdges(const node root, bool directed) const {
return tlp::bfsEdges(this, root, directed);
}

std::vector<edge> GraphAbstract::dfsEdges(const node root, bool directed) const {
return tlp::dfsEdges(this, root, directed);
}

std::vector<edge> GraphAbstract::dfsEdges(bool directed) const {
return tlp::dfsEdges(this, directed);
}

void GraphAbstract::dfs(node root, const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed) const {
tlp::dfs(this, root, inVisitCallback, outVisitCallback, directed);
}

void GraphAbstract::dfs(const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed) const {
tlp::dfs(this, inVisitCallback, outVisitCallback, directed);
}
22 changes: 21 additions & 1 deletion library/talipot-core/src/GraphDecorator.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (C) 2019-2023 The Talipot developers
* Copyright (C) 2019-2024 The Talipot developers
*
* Talipot is a fork of Tulip, created by David Auber
* and the Tulip development Team from LaBRI, University of Bordeaux
Expand Down Expand Up @@ -431,6 +431,22 @@ std::vector<node> GraphDecorator::dfs(const node root, bool directed) const {
return graph_component->dfs(root, directed);
}
//============================================================
std::vector<node> GraphDecorator::dfs(bool directed) const {
return graph_component->dfs(directed);
}
//============================================================
void GraphDecorator::dfs(node root, const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed) const {
graph_component->dfs(root, inVisitCallback, outVisitCallback, directed);
}
//============================================================
void GraphDecorator::dfs(const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed) const {
graph_component->dfs(inVisitCallback, outVisitCallback, directed);
}
//============================================================
std::vector<edge> GraphDecorator::bfsEdges(const node root, bool directed) const {
return graph_component->bfsEdges(root, directed);
}
Expand All @@ -439,6 +455,10 @@ std::vector<edge> GraphDecorator::dfsEdges(const node root, bool directed) const
return graph_component->dfsEdges(root, directed);
}
//============================================================
std::vector<edge> GraphDecorator::dfsEdges(bool directed) const {
return graph_component->dfsEdges(directed);
}
//============================================================
const std::vector<edge> &GraphDecorator::edges() const {
return graph_component->edges();
}
Expand Down
97 changes: 69 additions & 28 deletions library/talipot-core/src/GraphTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,42 +580,65 @@ vector<edge> bfsEdges(const Graph *graph, bool directed) {
//======================================================================

static void dfs(const Graph *graph, node root, NodeVectorProperty<bool> &visited,
vector<node> &nodes, vector<edge> &edges, bool directed = false) {
const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback, bool directed,
vector<node> *nodes = nullptr, vector<edge> *edges = nullptr) {
if (visited[root]) {
return;
}

nodes.reserve(nodes.size() + graph->numberOfNodes());
edges.reserve(edges.size() + graph->numberOfEdges());
if (nodes) {
nodes->reserve(nodes->size() + graph->numberOfNodes());
}
if (edges) {
edges->reserve(edges->size() + graph->numberOfEdges());
}

stack<pair<edge, node>> toVisit;
toVisit.push({edge(), root});
stack<tuple<edge, node, node>> toVisit;
toVisit.push({edge(), root, node()});
visited[root] = true;

while (!toVisit.empty()) {
auto [edge, currentNode] = toVisit.top();
auto [edge, currentNode, outNode] = toVisit.top();
toVisit.pop();
nodes.push_back(currentNode);
if (edge.isValid()) {
edges.push_back(edge);
if (nodes) {
nodes->push_back(currentNode);
}
if (edges && edge.isValid()) {
edges->push_back(edge);
}

if (!inVisitCallback(graph, currentNode)) {
return;
}

auto incidentEdges = iteratorVector(getIncidentEdgesIterator(
graph, currentNode, directed ? EdgeType::DIRECTED : EdgeType::UNDIRECTED));
uint i = 0;
for (auto e : reversed(incidentEdges)) {
node neigh = graph->opposite(e, currentNode);
if (!visited[neigh]) {
visited[neigh] = true;
toVisit.push({e, neigh});
toVisit.push({e, neigh, ++i == 1 ? currentNode : node()});
}
}

if (incidentEdges.empty() && !outVisitCallback(graph, currentNode)) {
return;
}

if (outNode.isValid() && !outVisitCallback(graph, outNode)) {
return;
}
}
}

static inline pair<vector<node>, vector<edge>> performDfs(const Graph *graph, node root,
bool directed = false) {
vector<node> nodes;
vector<edge> edges;
static inline void performDfs(const Graph *graph, node root,
const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed, vector<node> *nodes = nullptr,
vector<edge> *edges = nullptr) {

if (!graph->isEmpty()) {
if (!root.isValid()) {
root = graph->getSource();
Expand All @@ -628,42 +651,60 @@ static inline pair<vector<node>, vector<edge>> performDfs(const Graph *graph, no
assert(graph->isElement(root));
NodeVectorProperty<bool> visited(graph);
visited.setAll(false);
dfs(graph, root, visited, nodes, edges, directed);
dfs(graph, root, visited, inVisitCallback, outVisitCallback, directed, nodes, edges);
}
return {nodes, edges};
}

static inline bool continueVisit(const Graph *, node) {
return true;
}

// dfs from a root node
std::vector<node> dfs(const Graph *graph, node root, bool directed) {
auto [nodes, edges] = performDfs(graph, root, directed);
vector<node> dfs(const Graph *graph, node root, bool directed) {
vector<node> nodes;
performDfs(graph, root, continueVisit, continueVisit, directed, &nodes);
return nodes;
}

std::vector<edge> dfsEdges(const Graph *graph, node root, bool directed) {
auto [nodes, edges] = performDfs(graph, root, directed);
return edges;
void dfs(const Graph *graph, node root,
const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback, bool directed) {
performDfs(graph, root, inVisitCallback, outVisitCallback, directed);
}

static inline pair<vector<node>, vector<edge>> performCumulativeDfs(const Graph *graph,
bool directed) {
vector<node> nodes;
vector<edge> dfsEdges(const Graph *graph, node root, bool directed) {
vector<edge> edges;
performDfs(graph, root, continueVisit, continueVisit, directed, nullptr, &edges);
return edges;
}

static inline void
performCumulativeDfs(const Graph *graph,
const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback,
bool directed, vector<node> *nodes = nullptr, vector<edge> *edges = nullptr) {
NodeVectorProperty<bool> visited(graph);
visited.setAll(false);
for (auto n : graph->nodes()) {
dfs(graph, n, visited, nodes, edges, directed);
dfs(graph, n, visited, inVisitCallback, outVisitCallback, directed, nodes, edges);
}
return {nodes, edges};
}

// cumulative dfs from every node of the graph
std::vector<tlp::node> dfs(const Graph *graph, bool directed) {
auto [nodes, edges] = performCumulativeDfs(graph, directed);
vector<node> nodes;
performCumulativeDfs(graph, continueVisit, continueVisit, directed, &nodes);
return nodes;
}

void dfs(const Graph *graph, const std::function<bool(const Graph *, node)> &inVisitCallback,
const std::function<bool(const Graph *, node)> &outVisitCallback, bool directed) {
performCumulativeDfs(graph, inVisitCallback, outVisitCallback, directed);
}

std::vector<tlp::edge> dfsEdges(const Graph *graph, bool directed) {
auto [nodes, edges] = performCumulativeDfs(graph, directed);
vector<edge> edges;
performCumulativeDfs(graph, continueVisit, continueVisit, directed, nullptr, &edges);
return edges;
}

Expand Down
Loading

0 comments on commit e2b1400

Please sign in to comment.