Skip to content

Commit

Permalink
New feature: convert networkx attributes to networkit attributes (#1191)
Browse files Browse the repository at this point in the history
* add attribute getters to python

* remove unused graph object from attribute wrapper classes

* add attribute conversion to nx2nk

* add optional custom type mapping

* fix none case error for type map

* add None to parameter type hints

* fix edgeById for directed graphs

* fix tests, add test for custom typemap

* fix CI

* change print to warn

* update tests to check for warnings
  • Loading branch information
bernlu committed Apr 3, 2024
1 parent 28f8ff3 commit b99805a
Show file tree
Hide file tree
Showing 8 changed files with 606 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/scripts/core_sanitizers_coverage.sh
Expand Up @@ -2,7 +2,7 @@

python3 -m venv pyenv && . pyenv/bin/activate
pip3 install --upgrade pip
pip3 install coveralls cython gcovr matplotlib requests setuptools tabulate numpy
pip3 install coveralls cython gcovr matplotlib requests setuptools tabulate numpy networkx

mkdir core_build && cd "$_"
export CPU_COUNT=$(python3 $GITHUB_WORKSPACE/.github/workflows/scripts/get_core_count.py)
Expand Down
32 changes: 31 additions & 1 deletion include/networkit/graph/Graph.hpp
Expand Up @@ -581,6 +581,36 @@ class Graph final {
return edgeAttributes().attach<std::string>(name);
}

auto getNodeIntAttribute(const std::string &name) {
nodeAttributes().theGraph = this;
return nodeAttributes().get<int>(name);
}

auto getEdgeIntAttribute(const std::string &name) {
edgeAttributes().theGraph = this;
return edgeAttributes().get<int>(name);
}

auto getNodeDoubleAttribute(const std::string &name) {
nodeAttributes().theGraph = this;
return nodeAttributes().get<double>(name);
}

auto getEdgeDoubleAttribute(const std::string &name) {
edgeAttributes().theGraph = this;
return edgeAttributes().get<double>(name);
}

auto getNodeStringAttribute(const std::string &name) {
nodeAttributes().theGraph = this;
return nodeAttributes().get<std::string>(name);
}

auto getEdgeStringAttribute(const std::string &name) {
edgeAttributes().theGraph = this;
return edgeAttributes().get<std::string>(name);
}

void detachNodeAttribute(std::string const &name) {
nodeAttributes().theGraph = this;
nodeAttributes().detach(name);
Expand Down Expand Up @@ -1695,7 +1725,7 @@ class Graph final {
forNodesWhile([&] { return !found; },
[&](node u) {
forNeighborsOf(u, [&](node v) {
if (v < u)
if (!this->isDirected() && v < u)
return;
auto uvId = edgeId(u, v);
if (uvId == id) {
Expand Down
4 changes: 4 additions & 0 deletions networkit/cpp/graph/test/GraphGTest.cpp
Expand Up @@ -1929,10 +1929,14 @@ TEST_P(GraphGTest, testEdgeIndexResolver) {
G.addEdge(5, 6);
G.addEdge(2, 2);

if (G.isDirected())
G.addEdge(3, 2);

std::map<std::pair<node, node>, edgeid> expectedEdges;
expectedEdges[std::make_pair(0, 0)] = 0;
expectedEdges[std::make_pair(5, 6)] = 1;
expectedEdges[std::make_pair(2, 2)] = 2;
expectedEdges[std::make_pair(3, 2)] = 3;

G.forEdges([&](node, node, edgeid eid) {
auto edge = G.edgeById(eid);
Expand Down
6 changes: 6 additions & 0 deletions networkit/graph.pxd
Expand Up @@ -90,10 +90,16 @@ cdef extern from "<networkit/graph/Graph.hpp>":
_NodeIntAttribute attachNodeIntAttribute(string) except +
_NodeDoubleAttribute attachNodeDoubleAttribute(string) except +
_NodeStringAttribute attachNodeStringAttribute(string) except +
_NodeIntAttribute getNodeIntAttribute(string) except +
_NodeDoubleAttribute getNodeDoubleAttribute(string) except +
_NodeStringAttribute getNodeStringAttribute(string) except +
void detachNodeAttribute(string) except +
_EdgeIntAttribute attachEdgeIntAttribute(string) except +
_EdgeDoubleAttribute attachEdgeDoubleAttribute(string) except +
_EdgeStringAttribute attachEdgeStringAttribute(string) except +
_EdgeIntAttribute getEdgeIntAttribute(string) except +
_EdgeDoubleAttribute getEdgeDoubleAttribute(string) except +
_EdgeStringAttribute getEdgeStringAttribute(string) except +
void detachEdgeAttribute(string) except +

cdef extern from "<networkit/graph/Graph.hpp>":
Expand Down
79 changes: 73 additions & 6 deletions networkit/graph.pyx
Expand Up @@ -989,6 +989,42 @@ cdef class Graph:
elif ofType == str:
return NodeAttribute(NodeStringAttribute().setThis(self._this.attachNodeStringAttribute(stdstring(name)), &self._this), str)

def getNodeAttribute(self, name, ofType):
"""
getNodeAttribute(name, ofType)
Gets a node attribute that is already attached to the graph and returns it.
.. code-block::
A = G.getNodeAttribute("attributeIdentifier", ofType)
Notes
-----
Using node attributes is in experimental state. The API may change in future updates.
Parameters
----------
name : str
Name for this attribute
ofType : type
Type of the attribute (either int, float, or str)
Returns
-------
networkit.graph.NodeAttribute
The resulting node attribute container.
"""
if not isinstance(name, str):
raise Exception("Attribute name has to be a string")

if ofType == int:
return NodeAttribute(NodeIntAttribute().setThis(self._this.getNodeIntAttribute(stdstring(name)), &self._this), int)
elif ofType == float:
return NodeAttribute(NodeDoubleAttribute().setThis(self._this.getNodeDoubleAttribute(stdstring(name)), &self._this), float)
elif ofType == str:
return NodeAttribute(NodeStringAttribute().setThis(self._this.getNodeStringAttribute(stdstring(name)), &self._this), str)

def detachNodeAttribute(self, name):
"""
detachNodeAttribute(name)
Expand Down Expand Up @@ -1054,6 +1090,43 @@ cdef class Graph:
elif ofType == str:
return EdgeAttribute(EdgeStringAttribute().setThis(self._this.attachEdgeStringAttribute(stdstring(name)), &self._this), str)


def getEdgeAttribute(self, name, ofType):
"""
getEdgeAttribute(name, ofType)
Gets an edge attribute that is already attached to the graph and returns it.
.. code-block::
A = G.getEdgeAttribute("attributeIdentifier", ofType)
Notes
-----
Using edge attributes is in experimental state. The API may change in future updates.
Parameters
----------
name : str
Name for this attribute
ofType : type
Type of the attribute (either int, float, or str)
Returns
-------
networkit.graph.EdgeAttribute
The resulting edge attribute container.
"""
if not isinstance(name, str):
raise Exception("Attribute name has to be a string")

if ofType == int:
return EdgeAttribute(EdgeIntAttribute().setThis(self._this.getEdgeIntAttribute(stdstring(name)), &self._this), int)
elif ofType == float:
return EdgeAttribute(EdgeDoubleAttribute().setThis(self._this.getEdgeDoubleAttribute(stdstring(name)), &self._this), float)
elif ofType == str:
return EdgeAttribute(EdgeStringAttribute().setThis(self._this.getEdgeStringAttribute(stdstring(name)), &self._this), str)

def detachEdgeAttribute(self, name):
"""
detachEdgeAttribute(name)
Expand Down Expand Up @@ -1129,7 +1202,6 @@ cdef class NodeIntAttribute:

cdef setThis(self, _NodeIntAttribute& other, _Graph* G):
self._this.swap(other)
self._G = G
return self

def __getitem__(self, node):
Expand Down Expand Up @@ -1174,7 +1246,6 @@ cdef class NodeIntAttribute:
cdef class NodeDoubleAttribute:
cdef setThis(self, _NodeDoubleAttribute& other, _Graph* G):
self._this.swap(other)
self._G = G
return self

def __getitem__(self, node):
Expand Down Expand Up @@ -1218,7 +1289,6 @@ cdef class NodeStringAttribute:

cdef setThis(self, _NodeStringAttribute& other, _Graph* G):
self._this.swap(other)
self._G = G
return self

def getName(self):
Expand Down Expand Up @@ -1326,7 +1396,6 @@ cdef class EdgeIntAttribute:

cdef setThis(self, _EdgeIntAttribute& other, _Graph* G):
self._this.swap(other)
self._G = G
return self

def __getitem__(self, edgeIdORnodePair):
Expand Down Expand Up @@ -1384,7 +1453,6 @@ cdef class EdgeIntAttribute:
cdef class EdgeDoubleAttribute:
cdef setThis(self, _EdgeDoubleAttribute& other, _Graph* G):
self._this.swap(other)
self._G = G
return self

def __getitem__(self, edgeIdORnodePair):
Expand Down Expand Up @@ -1442,7 +1510,6 @@ cdef class EdgeStringAttribute:

cdef setThis(self, _EdgeStringAttribute& other, _Graph* G):
self._this.swap(other)
self._G = G
return self

def __getitem__(self, edgeIdORnodePair):
Expand Down

0 comments on commit b99805a

Please sign in to comment.