Skip to content

Commit

Permalink
Merge pull request #386 from manpen/feature/FasterTranspose
Browse files Browse the repository at this point in the history
Faster Graph::transpose
  • Loading branch information
avdgrinten committed Sep 3, 2019
2 parents 436aaff + 73533ab commit 555e0f0
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 11 deletions.
37 changes: 30 additions & 7 deletions networkit/cpp/graph/Graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include <sstream>

#include <networkit/graph/Graph.hpp>
#include <networkit/graph/GraphBuilder.hpp>

namespace NetworKit {

Expand Down Expand Up @@ -1071,21 +1070,45 @@ std::vector<node> Graph::neighbors(node u) const {
Graph Graph::transpose() const {
if (directed == false) {
throw std::runtime_error("The transpose of an undirected graph is "
"identical to the original graph.");
"identical to the original graph.");
}

GraphBuilder gB(z, weighted, true);
Graph GTranspose(z, weighted, true);

this->forEdges([&](node u, node v) { gB.addHalfEdge(v, u, weight(u, v)); });
// prepare edge id storage if input has indexed edges
GTranspose.edgesIndexed = edgesIndexed;
GTranspose.omega = omega;
if (edgesIndexed) {
GTranspose.inEdgeIds.resize(z);
GTranspose.outEdgeIds.resize(z);
}

Graph GTranspose = gB.toGraph(true);
for (node u = 0; u < z; ++u) {
if (!exists[u]) {
#pragma omp parallel for
for (omp_index u = 0; u < static_cast<omp_index>(z); ++u) {
if (exists[u]) {
GTranspose.preallocateDirected(u, degreeIn(u), degreeOut(u));

forInEdgesOf(u, [&] (node, node v, edgeweight w, edgeid id) {
GTranspose.addPartialOutEdge(unsafe, u, v, w, id);
});

forEdgesOf(u, [&] (node, node v, edgeweight w, edgeid id) {
GTranspose.addPartialInEdge(unsafe, u, v, w, id);
});

} else {
#pragma omp critical
GTranspose.removeNode(u);
}
}

GTranspose.setEdgeCount(unsafe, numberOfEdges());
GTranspose.setNumberOfSelfLoops(unsafe, numberOfSelfLoops());
GTranspose.t = t;
GTranspose.setName(getName() + "Transpose");

assert(GTranspose.checkConsistency());

return GTranspose;
}

Expand Down
50 changes: 46 additions & 4 deletions networkit/test/test_graph.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
import unittest
import random
import networkit as nk

class TestGraph(unittest.TestCase):
Expand All @@ -13,8 +14,7 @@ def getSmallGraph(self, weighted=False, directed=False):

return G

def testSubgraphFromNodes(self):
# Directed
def testSubgraphFromNodesDirected(self):
G = self.getSmallGraph(True, True)

res = G.subgraphFromNodes([0])
Expand All @@ -39,8 +39,8 @@ def testSubgraphFromNodes(self):
self.assertEqual(res.numberOfNodes(), 4)
self.assertEqual(res.numberOfEdges(), 4)

# Undirected
G = G.toUndirected()
def testSubgraphFromNodesUndirected(self):
G = self.getSmallGraph(True, False)

res = G.subgraphFromNodes([0])
self.assertTrue(res.isWeighted())
Expand Down Expand Up @@ -121,5 +121,47 @@ def testNeighbors(self):
self.assertEqual(sorted(G.neighbors(2)), [0, 1, 3])
self.assertEqual(sorted(G.neighbors(3)), [1, 2])

def testGraphTranspose(self):
nk.setSeed(1, True)
G = nk.generators.ErdosRenyiGenerator(100, 0.2, True).generate()

for i in range(20):
u = G.randomNode()
if not G.hasEdge(u, u):
G.addEdge(u, u)
self.assertGreater(G.numberOfSelfLoops(), 0)

# Delete a few nodes
for i in range(10):
G.removeNode(G.randomNode())
self.assertGreater(G.numberOfSelfLoops(), 0)

# Assign random weights
GWeighted = nk.Graph(G, True, True)
for u, v in GWeighted.edges():
GWeighted.setWeight(u, v, random.random())

GWeighted.indexEdges()

GTrans = GWeighted.transpose()

for u, v in GWeighted.edges():
self.assertEqual(GWeighted.edgeId(u, v), GTrans.edgeId(v, u))
self.assertEqual(GWeighted.weight(u, v), GTrans.weight(v, u))

for v, u in GTrans.edges():
self.assertEqual(GWeighted.edgeId(u, v), GTrans.edgeId(v, u))
self.assertEqual(GWeighted.weight(u, v), GTrans.weight(v, u))

for u in range(GWeighted.upperNodeIdBound()):
self.assertEqual(GWeighted.hasNode(u), GTrans.hasNode(u))

self.assertEqual(GWeighted.upperEdgeIdBound(), GTrans.upperEdgeIdBound())
self.assertEqual(GWeighted.upperNodeIdBound(), GTrans.upperNodeIdBound())
self.assertEqual(GWeighted.numberOfSelfLoops(), GTrans.numberOfSelfLoops())
self.assertEqual(GWeighted.numberOfNodes(), GTrans.numberOfNodes())
self.assertEqual(GWeighted.numberOfEdges(), GTrans.numberOfEdges())


if __name__ == "__main__":
unittest.main()

0 comments on commit 555e0f0

Please sign in to comment.