Revision e0f4bbd19d892da805db949a5b98c3dfa9842abc authored by Fabian Brandt on 23 April 2021, 09:51:40 UTC, committed by GitHub on 23 April 2021, 09:51:40 UTC
1 parent 29b3fba
viz.pyx
# distutils: language=c++
from libc.stdint cimport uint64_t
from libcpp.string cimport string
from libcpp cimport bool as bool_t
from libcpp.vector cimport vector
from libcpp.utility cimport pair
ctypedef uint64_t count
ctypedef uint64_t index
ctypedef index node
ctypedef double coordinate
from .graph cimport _Graph, Graph
cdef extern from "<networkit/viz/Point.hpp>" namespace "NetworKit" nogil:
cdef cppclass Point[T]:
Point()
Point(T x, T y)
T& operator[](const index i) except +
T& at(const index i) except +
cdef cppclass _Point2D "NetworKit::Point2D":
_Point2D()
pair[coordinate, coordinate] asPair()
cdef object toPoint2DVector(const vector[_Point2D]& v):
return [v[i].asPair() for i in range(v.size())]
cdef object toNodePoint2DVector(const vector[pair[node, _Point2D]]& v):
return [(v[i].first, v[i].second.asPair()) for i in range(v.size())]
def stdstring(pystring):
""" convert a Python string to a bytes object which is automatically coerced to std::string"""
pybytes = pystring.encode("utf-8")
return pybytes
cdef extern from "<networkit/viz/GraphLayoutAlgorithm.hpp>":
cdef cppclass _GraphLayoutAlgorithm "NetworKit::GraphLayoutAlgorithm"[T]:
_GraphLayoutAlgorithm(_Graph, count) except +
count numEdgeCrossings() except +
vector[Point[double]] getCoordinates() except +
bool_t writeGraphToGML(string path) except +
bool_t writeKinemage(string path) except +
cdef class GraphLayoutAlgorithm:
"""Abstract base class for graph drawing algorithms"""
cdef _GraphLayoutAlgorithm[double] *_this
cdef Graph _G
def __init__(self, *args, **kwargs):
if type(self) == GraphLayoutAlgorithm:
raise RuntimeError("Error, you may not use GraphLayoutAlgorithm directly, use a sub-class instead")
def __dealloc__(self):
self._G = None # just to be sure the graph is deleted
def numEdgeCrossings(self):
""" Computes approximation (in parallel) of the Spanning Edge Centrality. """
if self._this == NULL:
raise RuntimeError("Error, object not properly initialized")
return self._this.numEdgeCrossings()
def getCoordinates(self):
""" Computes approximation (in parallel) of the Spanning Edge Centrality. """
if self._this == NULL:
raise RuntimeError("Error, object not properly initialized")
cdef pair[double, double] pr = pair[double, double](0, 0)
pointCoord = self._this.getCoordinates()
cdef vector[pair[double, double]] pairCoord = vector[pair[double, double]]()
for pt in pointCoord:
pr = pair[double, double](pt[0], pt[1])
pairCoord.push_back(pr)
return pairCoord
def writeGraphToGML(self, path):
"""Writes the graph and its layout to a .gml file at the specified path
path: string
Path where the graph file should be created"""
if self._this == NULL:
raise RuntimeError("Error, object not properly initialized")
return self._this.writeGraphToGML(stdstring(path))
def writeKinemage(self, string path):
"""Writes the graph and its layout to a file at the specified path
path: string
Path where the graph file should be created"""
if self._this == NULL:
raise RuntimeError("Error, object not properly initialized")
return self._this.writeKinemage(stdstring(path))
cdef extern from "<networkit/viz/MaxentStress.hpp>" namespace "NetworKit":
enum _GraphDistance "NetworKit::MaxentStress::GraphDistance":
EDGE_WEIGHT,
ALGEBRAIC_DISTANCE
cdef extern from "<networkit/viz/MaxentStress.hpp>" namespace "NetworKit":
enum _LinearSolverType "NetworKit::MaxentStress::LinearSolverType":
LAMG,
CONJUGATE_GRADIENT_IDENTITY_PRECONDITIONER,
CONJUGATE_GRADIENT_DIAGONAL_PRECONDITIONER
cdef extern from "<networkit/viz/MaxentStress.hpp>":
cdef cppclass _MaxentStress "NetworKit::MaxentStress" (_GraphLayoutAlgorithm[double]):
_MaxentStress(_Graph G, count dim, count k, double tolerance, _LinearSolverType linearSolverType, bool_t fastComputation, _GraphDistance graphDistance) except +
_MaxentStress(_Graph G, count dim, const vector[Point[double]] coordinates, count k, double tolerance, _LinearSolverType linearSolverType, bool_t fastComputation, _GraphDistance graphDistance) except +
void run() except +
void scaleLayout() except +
double computeScalingFactor() except +
double fullStressMeasure() except +
double maxentMeasure() except +
double meanDistanceError() except +
double ldme() except +
void setQ(double q) except +
void setAlpha(double alpha) except +
void setAlphaReduction(double alphaReduction) except +
void setFinalAlpha(double finalAlpha) except +
void setConvergenceThreshold(double convThreshold) except +
double getRhs() except +
double getApproxEntropyTerm() except +
double getSolveTime() except +
cdef class MaxentStress (GraphLayoutAlgorithm):
"""
Implementation of MaxentStress by Gansner et al. using a Laplacian system solver.
@see Gansner, Emden R., Yifan Hu, and Steve North. "A maxent-stress model for graph layout."
Visualization and Computer Graphics, IEEE Transactions on 19, no. 6 (2013): 927-940.
Parameters
----------
G : networkit.Graph
The graph to be handled. Should be connected, otherwise the run() and runAlgo() methods will fail.
dim: count
Number of dimensions.
count: k
coordinates: vector[pair[double, double]]
The coordinates we want to draw in.
tolerance: double
The tolerance we want our solver to have.
linearSolverType: _LinearSolverType
The type of linear solver we wish to use.
fastComputation: bool
Decides whether or not slightly faster computation should be employed, leading to slightly worse results.
graphDistance: _GraphDistance
Decides what type of graph distance should be utilised.
"""
LAMG = 0
CONJUGATE_GRADIENT_IDENTITY_PRECONDITIONER = 1
CONJUGATE_GRADIENT_DIAGONAL_PRECONDITIONER = 2
EDGE_WEIGHT = 0
ALGEBRAIC_DISTANCE = 1
def __cinit__(self, Graph G, count dim, count k, vector[pair[double, double]] coordinates = [], double tolerance = 1e-5, _LinearSolverType linearSolverType = LAMG, bool_t fastComputation = False, _GraphDistance graphDistance = EDGE_WEIGHT):
cdef Point[double] p = Point[double](0, 0)
cdef vector[Point[double]] pointCoordinates = vector[Point[double]]()
for pr in coordinates:
p = Point[double](pr.first, pr.second)
pointCoordinates.push_back(p)
if (coordinates.size() != 0):
self._this = new _MaxentStress(G._this, dim, pointCoordinates, k, tolerance, linearSolverType, fastComputation, graphDistance)
else:
self._this = new _MaxentStress(G._this, dim, k, tolerance, linearSolverType, fastComputation, graphDistance)
def __dealloc__(self):
del self._this
def run(self):
"""Approximates a graph layout with the maxent-stress algorithm"""
(<_MaxentStress*>(self._this)).run()
return self
def scaleLayout(self):
"""Scale the layout computed by run() by a scalar s to minimize \sum_{u,v \in V} w_{uv} (s ||x_u - x_v|| - d_{uv}||)^2"""
(<_MaxentStress*>(self._this)).scaleLayout()
return self
def computeScalingFactor(self):
"""Computes a scalar s s.t. \sum_{u,v \in V} w_{uv} (s ||x_u - x_v|| - d_{uv}||)^2 is minimized"""
return (<_MaxentStress*>(self._this)).computeScalingFactor()
def fullStressMeasure(self):
"""Computes the full stress measure of the computed layout with run()"""
return (<_MaxentStress*>(self._this)).fullStressMeasure()
def maxentMeasure(self):
"""Computes the maxent stress measure for the computed layout with run()"""
return (<_MaxentStress*>(self._this)).maxentMeasure()
def meanDistanceError(self):
"""Computes mean distance error"""
return (<_MaxentStress*>(self._this)).meanDistanceError()
def ldme(self):
"""Computes the ldme"""
return (<_MaxentStress*>(self._this)).ldme()
def setQ(self, double q):
(<_MaxentStress*>(self._this)).setQ(q)
return self
def setAlpha(self, double alpha):
(<_MaxentStress*>(self._this)).setAlpha(alpha)
return self
def setAlphaReduction(self, double alphaReduction):
(<_MaxentStress*>(self._this)).setAlphaReduction(alphaReduction)
return self
def setFinalAlpha(self, double finalAlpha):
(<_MaxentStress*>(self._this)).setFinalAlpha(finalAlpha)
return self
def setConvergenceThreshold(self, double convThreshold):
(<_MaxentStress*>(self._this)).setConvergenceThreshold(convThreshold)
return self
def getRhs(self):
return (<_MaxentStress*>(self._this)).getRhs()
def getApproxEntropyTerm(self):
return (<_MaxentStress*>(self._this)).getApproxEntropyTerm()
def getSolveTime(self):
return (<_MaxentStress*>(self._this)).getSolveTime()
cdef extern from "<networkit/viz/PivotMDS.hpp>":
cdef cppclass _PivotMDS "NetworKit::PivotMDS" (_GraphLayoutAlgorithm[double]):
_PivotMDS(_Graph G, count dim, count numberOfPivots) except +
void run() except +
cdef class PivotMDS (GraphLayoutAlgorithm):
"""
Implementation of PivotMDS proposed by Brandes and Pich.
Parameters
----------
G: networkit.Graph
The graph to be handled by the algorithm.
dim: count
Number of dimensions.
numberOfPivots: count
Number of pivots for the algorithm.
"""
def __cinit__(self, Graph G, count dim, count numberOfPivots):
self._this = new _PivotMDS(G._this, dim, numberOfPivots)
def __dealloc__(self):
del self._this
def run(self):
"""Constructs a PivotMDS object for the given @a graph. The algorithm should embed the graph in @a dim dimensions using @a numberOfPivots pivots."""
(<_PivotMDS*>(self._this)).run()
return self
Computing file changes ...