Source code for sigmaepsilon.math.graph.utils
import numpy as np
from numba import jit
from numba.types import int64, Array
from numba.typed import Dict
from ..linalg.sparse import csr_matrix
__all__ = ["rooted_level_structure", "pseudo_peripheral_nodes"]
int64A = Array(int64, 1, "C")
[docs]
@jit(nopython=True, nogil=True, fastmath=False, cache=True)
def rooted_level_structure(adj: csr_matrix, root: int = 0) -> Dict:
"""
Turns a sparse adjacency matrix into a rooted level structure.
Parameters
----------
adj : csr_matrix
Adjacency matrix in CSR format.
root : int, Optional
Index of the root node. Default is 0.
Returns
-------
dict
A `numba` dictionary <int[:] : int[:, :]>, where the keys
refer to different levels, and the values are the indices
of nodes on that level.
"""
nN = len(adj.indptr) - 1
rls = Dict.empty(
key_type=int64,
value_type=int64A,
)
level = 0
rls[level] = np.array([root], dtype=np.int64)
nodes = np.zeros(nN, dtype=np.int64)
nodes[root] = 1
levelset = np.zeros(nN, dtype=np.int64)
nE = 1
while nE < nN:
levelset[:] = 0
for node in rls[level]:
neighbours = adj.irow(node)
levelset[neighbours] = 1
for iN in range(nN):
if nodes[iN] == 1:
levelset[iN] = 0
level += 1
rls[level] = np.where(levelset == 1)[0]
nE += len(rls[level])
for iN in range(nN):
if levelset[iN] == 1:
nodes[iN] = 1
return rls
[docs]
@jit(nopython=True, nogil=True, fastmath=False, cache=True)
def pseudo_peripheral_nodes(adj: csr_matrix) -> np.ndarray:
"""
Returns the indices of nodes that are possible candidates
for being peripheral nodes of a graph.
Parameters
----------
adj : csr_matrix
Adjacency matrix in CSR format.
Returns
-------
numpy.ndarray
Integer array of nodal indices.
"""
def length_width(RLS):
length = len(RLS)
width = 0
for i in range(length):
width = max(width, len(RLS[i]))
return length, width
RLS = rooted_level_structure(adj, root=0)
length, width = length_width(RLS)
while True:
nodes = RLS[len(RLS) - 1]
found = False
for _, node in enumerate(nodes):
iRLS = rooted_level_structure(adj, root=node)
iL, iW = length_width(iRLS)
if (iL > length) or (iL == length and iW < width):
RLS = iRLS
length = iL
width = iW
found = True
if not found:
nR = len(RLS[len(RLS) - 1]) + 1
res = np.zeros(nR, dtype=np.int64)
res[:-1] = RLS[len(RLS) - 1]
res[-1] = RLS[0][0]
return res