Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/networkx/linalg/laplacianmatrix.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/env/lib/python3.7/site-packages/networkx/linalg/laplacianmatrix.py Sat May 02 07:14:21 2020 -0400 @@ -0,0 +1,375 @@ +"""Laplacian matrix of graphs. +""" +# Copyright (C) 2004-2019 by +# Aric Hagberg <hagberg@lanl.gov> +# Dan Schult <dschult@colgate.edu> +# Pieter Swart <swart@lanl.gov> +# All rights reserved. +# BSD license. +import networkx as nx +from networkx.utils import not_implemented_for +__author__ = "\n".join(['Aric Hagberg <aric.hagberg@gmail.com>', + 'Pieter Swart (swart@lanl.gov)', + 'Dan Schult (dschult@colgate.edu)', + 'Alejandro Weinstein <alejandro.weinstein@gmail.com>']) +__all__ = ['laplacian_matrix', + 'normalized_laplacian_matrix', + 'directed_laplacian_matrix', + 'directed_combinatorial_laplacian_matrix'] + + +@not_implemented_for('directed') +def laplacian_matrix(G, nodelist=None, weight='weight'): + """Returns the Laplacian matrix of G. + + The graph Laplacian is the matrix L = D - A, where + A is the adjacency matrix and D is the diagonal matrix of node degrees. + + Parameters + ---------- + G : graph + A NetworkX graph + + nodelist : list, optional + The rows and columns are ordered according to the nodes in nodelist. + If nodelist is None, then the ordering is produced by G.nodes(). + + weight : string or None, optional (default='weight') + The edge data key used to compute each value in the matrix. + If None, then each edge has weight 1. + + Returns + ------- + L : SciPy sparse matrix + The Laplacian matrix of G. + + Notes + ----- + For MultiGraph/MultiDiGraph, the edges weights are summed. + + See Also + -------- + to_numpy_matrix + normalized_laplacian_matrix + laplacian_spectrum + """ + import scipy.sparse + if nodelist is None: + nodelist = list(G) + A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, + format='csr') + n, m = A.shape + diags = A.sum(axis=1) + D = scipy.sparse.spdiags(diags.flatten(), [0], m, n, format='csr') + return D - A + + +@not_implemented_for('directed') +def normalized_laplacian_matrix(G, nodelist=None, weight='weight'): + r"""Returns the normalized Laplacian matrix of G. + + The normalized graph Laplacian is the matrix + + .. math:: + + N = D^{-1/2} L D^{-1/2} + + where `L` is the graph Laplacian and `D` is the diagonal matrix of + node degrees. + + Parameters + ---------- + G : graph + A NetworkX graph + + nodelist : list, optional + The rows and columns are ordered according to the nodes in nodelist. + If nodelist is None, then the ordering is produced by G.nodes(). + + weight : string or None, optional (default='weight') + The edge data key used to compute each value in the matrix. + If None, then each edge has weight 1. + + Returns + ------- + N : NumPy matrix + The normalized Laplacian matrix of G. + + Notes + ----- + For MultiGraph/MultiDiGraph, the edges weights are summed. + See to_numpy_matrix for other options. + + If the Graph contains selfloops, D is defined as diag(sum(A,1)), where A is + the adjacency matrix [2]_. + + See Also + -------- + laplacian_matrix + normalized_laplacian_spectrum + + References + ---------- + .. [1] Fan Chung-Graham, Spectral Graph Theory, + CBMS Regional Conference Series in Mathematics, Number 92, 1997. + .. [2] Steve Butler, Interlacing For Weighted Graphs Using The Normalized + Laplacian, Electronic Journal of Linear Algebra, Volume 16, pp. 90-98, + March 2007. + """ + import scipy + import scipy.sparse + if nodelist is None: + nodelist = list(G) + A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, + format='csr') + n, m = A.shape + diags = A.sum(axis=1).flatten() + D = scipy.sparse.spdiags(diags, [0], m, n, format='csr') + L = D - A + with scipy.errstate(divide='ignore'): + diags_sqrt = 1.0 / scipy.sqrt(diags) + diags_sqrt[scipy.isinf(diags_sqrt)] = 0 + DH = scipy.sparse.spdiags(diags_sqrt, [0], m, n, format='csr') + return DH.dot(L.dot(DH)) + +############################################################################### +# Code based on +# https://bitbucket.org/bedwards/networkx-community/src/370bd69fc02f/networkx/algorithms/community/ + + +@not_implemented_for('undirected') +@not_implemented_for('multigraph') +def directed_laplacian_matrix(G, nodelist=None, weight='weight', + walk_type=None, alpha=0.95): + r"""Returns the directed Laplacian matrix of G. + + The graph directed Laplacian is the matrix + + .. math:: + + L = I - (\Phi^{1/2} P \Phi^{-1/2} + \Phi^{-1/2} P^T \Phi^{1/2} ) / 2 + + where `I` is the identity matrix, `P` is the transition matrix of the + graph, and `\Phi` a matrix with the Perron vector of `P` in the diagonal and + zeros elsewhere. + + Depending on the value of walk_type, `P` can be the transition matrix + induced by a random walk, a lazy random walk, or a random walk with + teleportation (PageRank). + + Parameters + ---------- + G : DiGraph + A NetworkX graph + + nodelist : list, optional + The rows and columns are ordered according to the nodes in nodelist. + If nodelist is None, then the ordering is produced by G.nodes(). + + weight : string or None, optional (default='weight') + The edge data key used to compute each value in the matrix. + If None, then each edge has weight 1. + + walk_type : string or None, optional (default=None) + If None, `P` is selected depending on the properties of the + graph. Otherwise is one of 'random', 'lazy', or 'pagerank' + + alpha : real + (1 - alpha) is the teleportation probability used with pagerank + + Returns + ------- + L : NumPy array + Normalized Laplacian of G. + + Notes + ----- + Only implemented for DiGraphs + + See Also + -------- + laplacian_matrix + + References + ---------- + .. [1] Fan Chung (2005). + Laplacians and the Cheeger inequality for directed graphs. + Annals of Combinatorics, 9(1), 2005 + """ + import scipy as sp + from scipy.sparse import spdiags, linalg + + P = _transition_matrix(G, nodelist=nodelist, weight=weight, + walk_type=walk_type, alpha=alpha) + + n, m = P.shape + + evals, evecs = linalg.eigs(P.T, k=1) + v = evecs.flatten().real + p = v / v.sum() + sqrtp = sp.sqrt(p) + Q = spdiags(sqrtp, [0], n, n) * P * spdiags(1.0 / sqrtp, [0], n, n) + I = sp.identity(len(G)) + + return I - (Q + Q.T) / 2.0 + + +@not_implemented_for('undirected') +@not_implemented_for('multigraph') +def directed_combinatorial_laplacian_matrix(G, nodelist=None, weight='weight', + walk_type=None, alpha=0.95): + r"""Return the directed combinatorial Laplacian matrix of G. + + The graph directed combinatorial Laplacian is the matrix + + .. math:: + + L = \Phi - (\Phi P + P^T \Phi) / 2 + + where `P` is the transition matrix of the graph and and `\Phi` a matrix + with the Perron vector of `P` in the diagonal and zeros elsewhere. + + Depending on the value of walk_type, `P` can be the transition matrix + induced by a random walk, a lazy random walk, or a random walk with + teleportation (PageRank). + + Parameters + ---------- + G : DiGraph + A NetworkX graph + + nodelist : list, optional + The rows and columns are ordered according to the nodes in nodelist. + If nodelist is None, then the ordering is produced by G.nodes(). + + weight : string or None, optional (default='weight') + The edge data key used to compute each value in the matrix. + If None, then each edge has weight 1. + + walk_type : string or None, optional (default=None) + If None, `P` is selected depending on the properties of the + graph. Otherwise is one of 'random', 'lazy', or 'pagerank' + + alpha : real + (1 - alpha) is the teleportation probability used with pagerank + + Returns + ------- + L : NumPy array + Combinatorial Laplacian of G. + + Notes + ----- + Only implemented for DiGraphs + + See Also + -------- + laplacian_matrix + + References + ---------- + .. [1] Fan Chung (2005). + Laplacians and the Cheeger inequality for directed graphs. + Annals of Combinatorics, 9(1), 2005 + """ + from scipy.sparse import spdiags, linalg + + P = _transition_matrix(G, nodelist=nodelist, weight=weight, + walk_type=walk_type, alpha=alpha) + + n, m = P.shape + + evals, evecs = linalg.eigs(P.T, k=1) + v = evecs.flatten().real + p = v / v.sum() + Phi = spdiags(p, [0], n, n) + + Phi = Phi.todense() + + return Phi - (Phi*P + P.T*Phi) / 2.0 + + +def _transition_matrix(G, nodelist=None, weight='weight', + walk_type=None, alpha=0.95): + """Returns the transition matrix of G. + + This is a row stochastic giving the transition probabilities while + performing a random walk on the graph. Depending on the value of walk_type, + P can be the transition matrix induced by a random walk, a lazy random walk, + or a random walk with teleportation (PageRank). + + Parameters + ---------- + G : DiGraph + A NetworkX graph + + nodelist : list, optional + The rows and columns are ordered according to the nodes in nodelist. + If nodelist is None, then the ordering is produced by G.nodes(). + + weight : string or None, optional (default='weight') + The edge data key used to compute each value in the matrix. + If None, then each edge has weight 1. + + walk_type : string or None, optional (default=None) + If None, `P` is selected depending on the properties of the + graph. Otherwise is one of 'random', 'lazy', or 'pagerank' + + alpha : real + (1 - alpha) is the teleportation probability used with pagerank + + Returns + ------- + P : NumPy array + transition matrix of G. + + Raises + ------ + NetworkXError + If walk_type not specified or alpha not in valid range + """ + + import scipy as sp + from scipy.sparse import identity, spdiags + if walk_type is None: + if nx.is_strongly_connected(G): + if nx.is_aperiodic(G): + walk_type = "random" + else: + walk_type = "lazy" + else: + walk_type = "pagerank" + + M = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, + dtype=float) + n, m = M.shape + if walk_type in ["random", "lazy"]: + DI = spdiags(1.0 / sp.array(M.sum(axis=1).flat), [0], n, n) + if walk_type == "random": + P = DI * M + else: + I = identity(n) + P = (I + DI * M) / 2.0 + + elif walk_type == "pagerank": + if not (0 < alpha < 1): + raise nx.NetworkXError('alpha must be between 0 and 1') + # this is using a dense representation + M = M.todense() + # add constant to dangling nodes' row + dangling = sp.where(M.sum(axis=1) == 0) + for d in dangling[0]: + M[d] = 1.0 / n + # normalize + M = M / M.sum(axis=1) + P = alpha * M + (1 - alpha) / n + else: + raise nx.NetworkXError("walk_type must be random, lazy, or pagerank") + + return P + + +# fixture for pytest +def setup_module(module): + import pytest + numpy = pytest.importorskip('numpy')