Class DHBGraph

Nested Relationships

Nested Types

Class Documentation

class DHBGraph

( ) parallel iterator methods.

For a detailed description of DHB, refer to the paper: [A Fast Data Structure for Dynamic Graphs Based on Hash-Indexed Adjacency Blocks (2022): https://drops.dagstuhl.de/storage/00lipics/lipics-vol233-sea2022/LIPIcs.SEA.2022.11/LIPIcs.SEA.2022.11.pdf)

Note

The DHB graph wrapper is still experimental. We tried to align our interface with the Graph class, though it may not yet be an “ad-hoc

replacement” class working with your client code as it did with GraphTODO:

  • [ ] Review the passing by value semantics for all lambdas passed to a method such as f(L handle). Instead, we might want to pass all lambdas by rvalue-reference as in f(L&& handle).

Public Types

using NodeIntAttribute = Attribute<PerNode, DHBGraph, int, false>
using NodeDoubleAttribute = Attribute<PerNode, DHBGraph, double, false>
using NodeStringAttribute = Attribute<PerNode, DHBGraph, std::string, false>
using EdgeIntAttribute = Attribute<PerEdge, DHBGraph, int, false>
using EdgeDoubleAttribute = Attribute<PerEdge, DHBGraph, double, false>
using EdgeStringAttribute = Attribute<PerEdge, DHBGraph, std::string, false>
using NodeIterator = NodeIteratorBase<DHBGraph, node, edgeweight>
using NodeRange = NodeRangeBase<DHBGraph, node, edgeweight>
using EdgeIterator = EdgeWeightTIterator<DHBGraph, node, edgeweight, EdgeT<node>>
using EdgeWeightIterator = EdgeWeightTIterator<DHBGraph, node, edgeweight, WeightedEdgeT<node, edgeweight>>
using EdgeRange = EdgeWeightTRange<DHBGraph, node, edgeweight, EdgeT<node>>
using EdgeWeightRange = EdgeWeightTRange<DHBGraph, node, edgeweight, WeightedEdgeT<node, edgeweight>>
using OutNeighborRange = NeighborRange<false>
using OutNeighborWeightRange = NeighborWeightRange<false>
using InNeighborWeightRange = NeighborWeightRange<true>

Public Functions

inline auto &nodeAttributes() noexcept
inline const auto &nodeAttributes() const noexcept
inline auto &edgeAttributes() noexcept
inline const auto &edgeAttributes() const noexcept
inline auto attachNodeIntAttribute(const std::string &name)
inline auto attachEdgeIntAttribute(const std::string &name)
inline auto attachNodeDoubleAttribute(const std::string &name)
inline auto attachEdgeDoubleAttribute(const std::string &name)
inline auto attachNodeStringAttribute(const std::string &name)
inline auto attachEdgeStringAttribute(const std::string &name)
inline auto getNodeIntAttribute(const std::string &name)
inline auto getEdgeIntAttribute(const std::string &name)
inline auto getNodeDoubleAttribute(const std::string &name)
inline auto getEdgeDoubleAttribute(const std::string &name)
inline auto getNodeStringAttribute(const std::string &name)
inline auto getEdgeStringAttribute(const std::string &name)
inline void detachNodeAttribute(std::string const &name)
inline void detachEdgeAttribute(std::string const &name)
DHBGraph(count n = 0, bool weighted = false, bool directed = false, bool edgesIndexed = false)

Create a graph of n nodes. The graph has assignable edge weights if weighted is set to true. If weighted is set to false each edge has edge weight 1.0 and any other weight assignment will be ignored.

Parameters:
  • n – Number of nodes.

  • weighted – If set to true, the graph has edge weights.

  • directed – If set to true, the graph will be directed.

template<class EdgeMerger = std::plus<edgeweight>>
inline DHBGraph(DHBGraph const &G, bool weighted, bool directed, bool edgesIndexed = false)
DHBGraph(std::initializer_list<WeightedEdge> edges)

Generate a weighted graph from a list of edges. (Useful for small graphs in unit tests that you do not want to read from a file.)

Parameters:

edges – [in] list of weighted edges

inline DHBGraph(const DHBGraph &other)

Create a graph as copy of other.

Parameters:

other – The graph to copy.

inline DHBGraph(DHBGraph &&other) noexcept

Default move constructor

~DHBGraph() = default

Default destructor

inline DHBGraph &operator=(DHBGraph &&other) noexcept

Default move assignment operator

inline DHBGraph &operator=(const DHBGraph &other)

Default copy assignment operator

void indexEdges(bool force = false)

EDGE IDS Initially assign integer edge identifiers.

Parameters:

force – Force re-indexing of edges even if they have already been indexed

inline bool hasEdgeIds() const noexcept

Checks if edges have been indexed

Returns:

bool if edges have been indexed

edgeid edgeId(node u, node v) const

Get the id of the given edge.

inline std::pair<node, node> edgeById(index id) const

Get the Edge (u,v) of the given id. (inverse to edgeId)

Note

Time complexity of this function is O(n).

inline index upperEdgeIdBound() const noexcept

Get an upper bound for the edge ids in the graph.

Returns:

An upper bound for the edge ids.

inline void sortEdges()

Sort edges according to accending neighbors for all vertices.

template<typename Lambda>
inline void sortEdges(Lambda &&lambda)

Default graph class: Sorts the adjacency arrays by a custom criterion. DHB: Sorts the neighbors by a custom criterion.

Parameters:

lambda – Lambda function used to sort the edges. Default graph class: It takes two WeightedEdge e1 and e2 as input parameters, returns true if e1 < e2, false otherwise. DHB: It takes node a_vertex, edgeweight a_weight, edgeid a_id, node b_vertex, edgeweight b_weight, edgeid b_id, as input parameters, and compares them according to lambda. TODO: Maybe we need to think of a nicer way for the interface in lambda.

inline void setEdgeCount(Unsafe, count edges)

Set edge count of the graph to edges.

Parameters:

edges – the edge count of a graph

inline void setUpperEdgeIdBound(Unsafe, edgeid newBound)

Set upper bound of edge count.

Parameters:

newBound – New upper edge id bound.

inline void setNumberOfSelfLoops(Unsafe, count loops)

Set the number of self-loops.

Parameters:

loops – New number of self-loops.

node addNode()

Add a new node to the graph and return it.

Returns:

The new node.

node addNodes(count numberOfNewNodes)

Add numberOfNewNodes new nodes.

Parameters:

numberOfNewNodes – Number of new nodes.

Returns:

The index of the last node added.

void removeNode(node v)

Removing a vertex is not supported in dhb. This will not remove the node but all neighbors of the given node v TODO: In the future, we might want to make removeNode to use the concurrent version of forNeighbors. But in that case, we need to make this function thread safe. Incoming as well as outgoing edges will be removed.

Parameters:

u – Node.

bool hasNode(node v) const noexcept

Check if node v exists in the graph.

Parameters:

v – Node.

Returns:

true if v exists, false otherwise.

count degree(node v) const

NODE PROPERTIES Returns the number of outgoing neighbors of v.

Note

The existence of the node is not checked. Calling this function with a non-existing node results in a segmentation fault. Node existence can be checked by calling hasNode(u).

Parameters:

v – Node.

Returns:

The number of outgoing neighbors.

count degreeIn(node v) const

Get the number of incoming neighbors of v.

Note

If the graph is not directed, the outgoing degree is returned.

Note

The existence of the node is not checked. Calling this function with a non-existing node results in a segmentation fault. Node existence can be checked by calling hasNode(u).

Parameters:

v – Node.

Returns:

The number of incoming neighbors.

inline count degreeOut(node v) const

Get the number of outgoing neighbors of v.

Note

The existence of the node is not checked. Calling this function with a non-existing node results in a segmentation fault. Node existence can be checked by calling hasNode(u).

Parameters:

v – Node.

Returns:

The number of outgoing neighbors.

bool isIsolated(node v) const

Check whether v is isolated, i.e. degree is 0.

Parameters:

v – Node. If graph is directed, the function runs in O(n) since it needs to iterate over all edges.

Returns:

true if the node is isolated (= degree is 0)

edgeweight weightedDegree(node u, bool countSelfLoopsTwice = false) const

Returns the weighted degree of u.

Parameters:
  • u – Node.

  • countSelfLoopsTwice – If set to true, self-loops will be counted twice.

Returns:

Weighted degree of u.

edgeweight weightedDegreeIn(node u, bool countSelfLoopsTwice = false) const

Returns the weighted in-degree of u.

Parameters:
  • u – Node.

  • countSelfLoopsTwice – If set to true, self-loops will be counted twice.

Returns:

Weighted in-degree of v.

bool addEdge(node u, node v, edgeweight ew = defaultEdgeWeight, bool do_update = true)

Insert an edge between the nodes u and v. If the graph is weighted you can optionally set a weight for this edge. The default weight is 1.0. Note: Multi-edges are not supported and will NOT be handled consistently by the graph data structure. It is possible to check for multi-edges by enabling parameter “checkForMultiEdges”. If already present, the new edge is not inserted. Enabling this check increases the complexity of the function to O(max(deg(u), deg(v))).

Parameters:
  • u – Endpoint of edge.

  • v – Endpoint of edge.

  • weight – Optional edge weight.

  • do_update – (Optional) If set to true, the function will update existing edges with new data; if false, it will only insert new edges.

Returns:

true if edge has been added, false otherwise (in case checkMultiEdge is set to true and the new edge would have been a multi-edge.)

void addEdges(std::vector<WeightedEdge> &&edges, bool do_update)

Adds a collection of weighted edges to the DHBGraph.

This function takes a vector of WeightedEdge objects and attempts to add them to the DHBGraph instance. It processes the edges in parallel. Depending on the value of do_update, the function either updates existing edges with new data or inserts new edges. After adding the edges, edge ids of the new edges will not be updated. Please call indexEdges(true) to index all the edges if needed.

Parameters:
  • weighted_edges – [in] A vector of WeightedEdge objects to be added to the graph. This parameter is an rvalue reference.

  • do_update – [in] A boolean flag indicating whether existing edges should be updated. If true, the function will update existing edges; if false, it will only insert new edges.

void addEdges(std::vector<Edge> &&edges, bool do_update)

Converts a vector of Edge objects to WeightedEdge and adds them to the DHBGraph.

Parameters:
  • edges – [in] A vector of Edge objects to be converted and added to the graph. This parameter is an rvalue reference.

  • do_update – [in] A boolean flag indicating whether existing edges should be updated. If true, the function will update existing edges; if false, it will only insert new edges.

bool removeEdge(node u, node v)

Removes the undirected edge {u,v}.

Parameters:
  • u – Endpoint of edge.

  • v – Endpoint of edge. DHB: Does not support maintaining compact edges or maintain sorted edges.

void removeAllEdges()

Removes all the edges in the graph.

template<typename Condition>
std::pair<count, count> removeAdjacentEdges(node u, Condition condition, bool edgesIn = false)

Removes edges adjacent to a node according to a specific criterion.

Parameters:
  • u – The node whose adjacent edges shall be removed.

  • condition – A function that takes a node as an input and returns a bool. If true the edge (u, v) is removed.

  • edgesIn – Whether in-going or out-going edges shall be removed.

Returns:

std::pair<count, count> The number of removed edges (first) and the number of removed self-loops (second).

void removeSelfLoops()

Removes all self-loops in the graph.

void swapEdge(node source_a, node target_a, node source_b, node target_b)

Swaps edge target of edge (source_a, target_a) with edge target of edge {source_b, target_b} such that (source_a, target_b) and (source_b, target_a).

Edge weights or edge ids are preserved.

A std::runtime_error() is thrown if:

  • edge (source_a, target_a) does not exist

  • edge (source_b, target_b) does not exist

  • edge (source_a, target_b) does already exist

  • edge (source_b, target_a) does already exist

bool hasEdge(node u, node v) const noexcept

Checks if undirected edge {u,v} exists in the graph.

Parameters:
  • u – Endpoint of edge.

  • v – Endpoint of edge.

Returns:

true if the edge exists, false otherwise.

inline bool isWeighted() const noexcept

Returns true if this graph supports edge weights other than 1.0.

Returns:

true if this graph supports edge weights other than 1.0.

inline bool isDirected() const noexcept

Return true if this graph supports directed edges.

Returns:

true if this graph supports directed edges.

inline bool isEmpty() const noexcept

Return true if graph contains no nodes.

Returns:

true if graph contains no nodes.

count numberOfNodes() const noexcept

Return the number of nodes in the graph.

Returns:

The number of nodes.

count numberOfEdges() const noexcept

Return the number of edges in the graph.

Returns:

The number of edges.

inline count numberOfSelfLoops() const noexcept

Return the number of loops {v,v} in the graph.

Note

This involves calculation, so store result if needed multiple times.

Returns:

The number of loops.

index upperNodeIdBound() const noexcept

Get an upper bound for the node ids in the graph.

Returns:

An upper bound for the node ids.

edgeweight weight(node u, node v) const

Retrieve the weight of an edge.

BEWARE: Running time is \Theta(1) for DHB implementation.

Parameters:
  • u – Endpoint of edge.

  • v – Endpoint of edge.

Returns:

Edge weight of edge {u,v} or 0 if edge does not exist.

void setWeight(node u, node v, edgeweight ew)

Set the weight of an edge. If the edge does not exist, it will be inserted.

Parameters:
  • u – [in] endpoint of edge

  • v – [in] endpoint of edge

  • weight – [in] edge weight

void setWeightAtIthNeighbor(Unsafe, node u, index i, edgeweight ew)

Set the weight to the i-th neighbour of u.

Parameters:
  • u – [in] endpoint of edge

  • i – [in] index of the nexight

  • weight – [in] edge weight

void increaseWeight(node u, node v, edgeweight ew)

Increase the weight of an edge. If the edge does not exist, it will be inserted.

Parameters:
  • u – [in] endpoint of edge

  • v – [in] endpoint of edge

  • weight – [in] edge weight

edgeweight totalEdgeWeight() const noexcept

Returns the sum of all edge weights.

Returns:

The sum of all edge weights.

inline NodeRange nodeRange() const noexcept

Get an iterable range over the nodes of the graph.

Returns:

Iterator range over the nodes of the graph.

inline EdgeRange edgeRange() const noexcept

Get an iterable range over the edges of the graph.

Returns:

Iterator range over the edges of the graph.

inline EdgeWeightRange edgeWeightRange() const noexcept

Get an iterable range over the edges of the graph and their weights.

Returns:

Iterator range over the edges of the graph and their weights.

inline NeighborRange<false> neighborRange(node u) const

Get an iterable range over the neighbors of .

Parameters:

u – Node.

Returns:

Iterator range over the neighbors of u.

inline NeighborWeightRange<false> weightNeighborRange(node u) const

Get an iterable range over the neighbors of u including the edge weights.

Parameters:

u – Node.

Returns:

Iterator range over pairs of neighbors of u and corresponding edge weights.

index indexOfNeighbor(node u, node v) const

Default Graph class: Returns the index of node v in the array of outgoing edges of node u. DHB: Returns the index of node v in the neighbors of outgoing edges of node u.

Parameters:
  • u – Node

  • v – Node

Returns:

index of node v in the array of outgoing edges of node u. TODO: We might want to support concurrency for this function in the future.

node getIthNeighbor(node u, index i) const

Return the i-th (outgoing) neighbor of u.

Parameters:
  • u – Node.

  • i – index; should be in [0, degreeOut(u))

Returns:

i-th (outgoing) neighbor of u, or none if no such neighbor exists.

node getIthNeighbor(Unsafe, node u, index i) const

Return the i-th (outgoing) neighbor of u.

Note

DHB does not support Unsafe functions. This function is logically the same as using getIthNeighbor(node, index).

Parameters:
  • u – Node.

  • i – index; should be in [0, degreeOut(u))

Returns:

i-th (outgoing) neighbor of u, or nullNodeId if no such neighbor exists.

edgeweight getIthNeighborWeight(node u, index i) const

Return the weight to the i-th (outgoing) neighbor of u.

Parameters:
  • u – Node.

  • i – index; should be in [0, degreeOut(u))

Returns:

edge weight to the i-th (outgoing) neighbor of u, or 0.0 if no such neighbor exists.

edgeweight getIthNeighborWeight(Unsafe, node u, index i) const

Return the weight to the i-th (outgoing) neighbor of u.

Note

DHB does not support Unsafe functions. This function is logically the same as using getIthNeighborWeight(node, index).

Parameters:
  • u – Node.

  • i – index; should be in [0, degreeOut(u))

Returns:

edge weight to the i-th (outgoing) neighbor of u, or 0.0 if no such neighbor exists.

std::pair<node, edgeweight> getIthNeighborWithWeight(node u, index i) const

Get i-th (outgoing) neighbor of u and the corresponding edge weight.

Parameters:
  • u – Node.

  • i – index; should be in [0, degreeOut(u))

Returns:

pair: (i-th (outgoing) neighbor of u, corresponding edge weight). Edge weight is defaultEdgeWeight if unweighted. Finally, if neighbor i of vertex u does not exist: returns (index none, 0.0).

std::pair<node, edgeweight> getIthNeighborWithWeight(Unsafe, node u, index i) const

Get i-th (outgoing) neighbor of u and the corresponding edge weight.

Note

DHB does not support Unsafe functions. This function is logically the same as using getIthNeighborWithWeight(node, index).

Parameters:
  • u – Node.

  • i – index; should be in [0, degreeOut(u))

Returns:

pair: i-th (outgoing) neighbor of u and the corresponding edge weight, or defaultEdgeWeight if unweighted.

std::pair<node, edgeid> getIthNeighborWithId(node u, index i) const

Get i-th (outgoing) neighbor of u and the corresponding edge id.

Parameters:
  • u – Node.

  • i – index; should be in [0, degreeOut(u))

Returns:

pair: i-th (outgoing) neighbor of u and the corresponding edge id, or none if no such neighbor exists.

template<typename L>
void forNodes(L handle) const

Iterate over all nodes of the graph and call handle (lambda closure).

Parameters:

handle – Takes parameter (node).

template<typename L>
void parallelForNodes(L handle) const

Iterate randomly over all nodes of the graph and call handle (lambda closure).

Parameters:

handle – Takes parameter (node).

template<typename C, typename L>
void forNodesWhile(C condition, L handle) const

Iterate over all nodes of the graph and call handle (lambda closure) as long as condition remains true. This allows for breaking from a node loop. TODO: Check if there’s a way to use omp parallel for in the loop without introducing atomic variable. TODO: We may want to have explict parallel in the function name.

Parameters:
  • condition – Returning false breaks the loop.

  • handle – Takes parameter (node).

template<typename L>
void forNodesInRandomOrder(L handle) const

Iterate randomly over all nodes of the graph and call handle (lambda closure).

Parameters:

handle – Takes parameter (node).

template<typename L>
void forNodePairs(L handle) const

Iterate over all undirected pairs of nodes and call handle (lambda closure).

Parameters:

handle – Takes parameters (node, node).

template<typename L>
void forNodePairsParallel(L handle) const

Iterate over all undirected pairs of nodes in parallel and call handle (lambda closure).

Parameters:

handle – Takes parameters (node, node).

template<typename L>
void forEdges(L handle) const

Iterate over all edges of the const graph and call handle (lambda closure).

Parameters:

handle – Takes parameters (node, node), (node, node, edgweight), (node, node, edgeid) or (node, node, edgeweight, edgeid).

template<typename L>
void parallelForEdges(L handle) const

Iterate in parallel over all edges of the const graph and call handle (lambda closure).

Parameters:

handle – Takes parameters (node, node) or (node, node, edgweight), (node, node, edgeid) or (node, node, edgeweight, edgeid).

template<typename L>
void forNeighborsOf(node u, L handle) const

Iterate over all neighbors of a node and call handle (lamdba closure).

Note

For directed graphs only outgoing edges from u are considered. A node is its own neighbor if there is a self-loop.

Parameters:
  • u – Node.

  • handle – Takes parameter (node) or (node, edgeweight) which is a neighbor of u.

template<typename L>
void forNeighborsOfParallel(node u, L handle) const

Iterate over all neighbors of a node and call handle (lamdba closure) concurrently.

Note

For directed graphs only outgoing edges from u are considered. A node is its own neighbor if there is a self-loop.

Parameters:
  • u – Node.

  • handle – Takes parameter (node) or (node, edgeweight) which is a neighbor of u.

template<typename L>
void forEdgesOf(node u, L handle) const

Iterate over all incident edges of a node and call handle (lamdba closure).

Note

For undirected graphs all edges incident to u are also outgoing edges.

Parameters:
  • u – Node.

  • handle – Takes parameters (node, node), (node, node, edgeweight), (node, node, edgeid) or (node, node, edgeweight, edgeid) where the first node is u and the second is a neighbor of u.

template<typename L>
void forEdgesOfParallel(node u, L handle) const

Iterate over all incident edges of a node and call handle (lamdba closure).

Note

For undirected graphs all edges incident to u are also outgoing edges.

Parameters:
  • u – Node.

  • handle – Takes parameters (node, node), (node, node, edgeweight), (node, node, edgeid) or (node, node, edgeweight, edgeid) where the first node is u and the second is a neighbor of u.

template<typename L>
void forInNeighborsOf(node u, L handle) const

Iterate over all neighbors of a node and call handler (lamdba closure). For directed graphs only incoming edges from u are considered.

template<typename L>
void forInNeighborsOfParallel(node u, L handle) const

Parallel version of forInNeighborsOf

template<typename L>
void forInEdgesOf(node u, L handle) const

Iterate over all incoming edges of a node and call handler (lamdba closure).

Handle takes parameters (u, v) or (u, v, w) where w is the edge weight.

Note

For undirected graphs all edges incident to u are also incoming edges.

template<typename L>
void forInEdgesOfParallel(node u, L handle) const

Parallel version of forInEdgesOf

template<typename L>
double sumForNodesParallel(L handle) const

Iterate in parallel over all nodes and sum (reduce +) the values returned by the handler

template<typename L>
double sumForEdgesParallel(L handle) const

Iterate in parallel over all edges and sum (reduce +) the values returned by the handler

class NeighborIterator

Class to iterate over the in/out neighbors of a node.

Public Types

using value_type = node
using reference = value_type&
using pointer = value_type*
using iterator_category = std::forward_iterator_tag
using difference_type = ptrdiff_t
using self = NeighborIterator

Public Functions

inline NeighborIterator(IteratorType it)
inline NeighborIterator()

WARNING: This contructor is required for Python and should not be used as the iterator is not initialized.

inline NeighborIterator &operator++()
inline NeighborIterator operator++(int)
inline NeighborIterator operator--()
inline NeighborIterator operator--(int)
inline bool operator==(NeighborIterator const &rhs) const
inline bool operator!=(NeighborIterator const &rhs) const
inline node operator*() const
template<bool InEdges = false>
class NeighborRange

Wrapper class to iterate over a range of the neighbors of a node within a for loop.

Public Functions

inline NeighborRange(DHBGraph const &G, node u)
inline NeighborRange()
inline NeighborIterator begin() const
inline NeighborIterator end() const
class NeighborWeightIterator

Class to iterate over the in/out neighbors of a node including the edge weights. Values are std::pair<node, edgeweight>.

Public Types

using value_type = std::pair<node, edgeweight>
using reference = value_type&
using pointer = value_type*
using iterator_category = std::forward_iterator_tag
using difference_type = ptrdiff_t
using self = NeighborWeightIterator

Public Functions

inline NeighborWeightIterator(IteratorType it)
inline NeighborWeightIterator()

WARNING: This contructor is required for Python and should not be used as the iterator is not initialized.

inline NeighborWeightIterator &operator++()
inline NeighborWeightIterator operator++(int)
inline NeighborWeightIterator operator--()
inline NeighborWeightIterator operator--(int)
inline bool operator==(NeighborWeightIterator const &rhs) const
inline bool operator!=(NeighborWeightIterator const &rhs) const
inline std::pair<node, edgeweight> operator*() const
template<bool InEdges = false>
class NeighborWeightRange

Wrapper class to iterate over a range of the neighbors of a node including the edge weights within a for loop. Values are std::pair<node, edgeweight>.

Public Functions

inline NeighborWeightRange(const DHBGraph &G, node u)
inline NeighborWeightRange()
inline NeighborWeightIterator begin() const
inline NeighborWeightIterator end() const