Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/networkx/linalg/algebraicconnectivity.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
| author | shellac |
|---|---|
| date | Mon, 01 Jun 2020 08:59:25 -0400 |
| parents | 79f47841a781 |
| children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/networkx/linalg/algebraicconnectivity.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,592 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2014 ysitu <ysitu@users.noreply.github.com> -# All rights reserved. -# BSD license. -# -# Author: ysitu <ysitu@users.noreply.github.com> -""" -Algebraic connectivity and Fiedler vectors of undirected graphs. -""" -from functools import partial -import networkx as nx -from networkx.utils import not_implemented_for -from networkx.utils import reverse_cuthill_mckee_ordering -from networkx.utils import random_state - -try: - from numpy import array, asmatrix, asarray, dot, ndarray, ones, sqrt, zeros - from numpy.linalg import norm, qr - from numpy.random import normal - from scipy.linalg import eigh, inv - from scipy.sparse import csc_matrix, spdiags - from scipy.sparse.linalg import eigsh, lobpcg - __all__ = ['algebraic_connectivity', 'fiedler_vector', 'spectral_ordering'] -except ImportError: - __all__ = [] - -try: - from scipy.linalg.blas import dasum, daxpy, ddot -except ImportError: - if __all__: - # Make sure the imports succeeded. - # Use minimal replacements if BLAS is unavailable from SciPy. - dasum = partial(norm, ord=1) - ddot = dot - - def daxpy(x, y, a): - y += a * x - return y - - -class _PCGSolver(object): - """Preconditioned conjugate gradient method. - - To solve Ax = b: - M = A.diagonal() # or some other preconditioner - solver = _PCGSolver(lambda x: A * x, lambda x: M * x) - x = solver.solve(b) - - The inputs A and M are functions which compute - matrix multiplication on the argument. - A - multiply by the matrix A in Ax=b - M - multiply by M, the preconditioner surragate for A - - Warning: There is no limit on number of iterations. - """ - - def __init__(self, A, M): - self._A = A - self._M = M or (lambda x: x.copy()) - - def solve(self, B, tol): - B = asarray(B) - X = ndarray(B.shape, order='F') - for j in range(B.shape[1]): - X[:, j] = self._solve(B[:, j], tol) - return X - - def _solve(self, b, tol): - A = self._A - M = self._M - tol *= dasum(b) - # Initialize. - x = zeros(b.shape) - r = b.copy() - z = M(r) - rz = ddot(r, z) - p = z.copy() - # Iterate. - while True: - Ap = A(p) - alpha = rz / ddot(p, Ap) - x = daxpy(p, x, a=alpha) - r = daxpy(Ap, r, a=-alpha) - if dasum(r) < tol: - return x - z = M(r) - beta = ddot(r, z) - beta, rz = beta / rz, beta - p = daxpy(p, z, a=beta) - - -class _CholeskySolver(object): - """Cholesky factorization. - - To solve Ax = b: - solver = _CholeskySolver(A) - x = solver.solve(b) - - optional argument `tol` on solve method is ignored but included - to match _PCGsolver API. - """ - - def __init__(self, A): - if not self._cholesky: - raise nx.NetworkXError('Cholesky solver unavailable.') - self._chol = self._cholesky(A) - - def solve(self, B, tol=None): - return self._chol(B) - - try: - from scikits.sparse.cholmod import cholesky - _cholesky = cholesky - except ImportError: - _cholesky = None - - -class _LUSolver(object): - """LU factorization. - - To solve Ax = b: - solver = _LUSolver(A) - x = solver.solve(b) - - optional argument `tol` on solve method is ignored but included - to match _PCGsolver API. - """ - - def __init__(self, A): - if not self._splu: - raise nx.NetworkXError('LU solver unavailable.') - self._LU = self._splu(A) - - def solve(self, B, tol=None): - B = asarray(B) - X = ndarray(B.shape, order='F') - for j in range(B.shape[1]): - X[:, j] = self._LU.solve(B[:, j]) - return X - - try: - from scipy.sparse.linalg import splu - _splu = partial(splu, permc_spec='MMD_AT_PLUS_A', diag_pivot_thresh=0., - options={'Equil': True, 'SymmetricMode': True}) - except ImportError: - _splu = None - - -def _preprocess_graph(G, weight): - """Compute edge weights and eliminate zero-weight edges. - """ - if G.is_directed(): - H = nx.MultiGraph() - H.add_nodes_from(G) - H.add_weighted_edges_from(((u, v, e.get(weight, 1.)) - for u, v, e in G.edges(data=True) - if u != v), weight=weight) - G = H - if not G.is_multigraph(): - edges = ((u, v, abs(e.get(weight, 1.))) - for u, v, e in G.edges(data=True) if u != v) - else: - edges = ((u, v, sum(abs(e.get(weight, 1.)) for e in G[u][v].values())) - for u, v in G.edges() if u != v) - H = nx.Graph() - H.add_nodes_from(G) - H.add_weighted_edges_from((u, v, e) for u, v, e in edges if e != 0) - return H - - -def _rcm_estimate(G, nodelist): - """Estimate the Fiedler vector using the reverse Cuthill-McKee ordering. - """ - G = G.subgraph(nodelist) - order = reverse_cuthill_mckee_ordering(G) - n = len(nodelist) - index = dict(zip(nodelist, range(n))) - x = ndarray(n, dtype=float) - for i, u in enumerate(order): - x[index[u]] = i - x -= (n - 1) / 2. - return x - - -def _tracemin_fiedler(L, X, normalized, tol, method): - """Compute the Fiedler vector of L using the TraceMIN-Fiedler algorithm. - - The Fiedler vector of a connected undirected graph is the eigenvector - corresponding to the second smallest eigenvalue of the Laplacian matrix of - of the graph. This function starts with the Laplacian L, not the Graph. - - Parameters - ---------- - L : Laplacian of a possibly weighted or normalized, but undirected graph - - X : Initial guess for a solution. Usually a matrix of random numbers. - This function allows more than one column in X to identify more than - one eigenvector if desired. - - normalized : bool - Whether the normalized Laplacian matrix is used. - - tol : float - Tolerance of relative residual in eigenvalue computation. - Warning: There is no limit on number of iterations. - - method : string - Should be 'tracemin_pcg', 'tracemin_chol' or 'tracemin_lu'. - Otherwise exception is raised. - - Returns - ------- - sigma, X : Two NumPy arrays of floats. - The lowest eigenvalues and corresponding eigenvectors of L. - The size of input X determines the size of these outputs. - As this is for Fiedler vectors, the zero eigenvalue (and - constant eigenvector) are avoided. - """ - n = X.shape[0] - - if normalized: - # Form the normalized Laplacian matrix and determine the eigenvector of - # its nullspace. - e = sqrt(L.diagonal()) - D = spdiags(1. / e, [0], n, n, format='csr') - L = D * L * D - e *= 1. / norm(e, 2) - - if normalized: - def project(X): - """Make X orthogonal to the nullspace of L. - """ - X = asarray(X) - for j in range(X.shape[1]): - X[:, j] -= dot(X[:, j], e) * e - else: - def project(X): - """Make X orthogonal to the nullspace of L. - """ - X = asarray(X) - for j in range(X.shape[1]): - X[:, j] -= X[:, j].sum() / n - - if method == 'tracemin_pcg': - D = L.diagonal().astype(float) - solver = _PCGSolver(lambda x: L * x, lambda x: D * x) - elif method == 'tracemin_chol' or method == 'tracemin_lu': - # Convert A to CSC to suppress SparseEfficiencyWarning. - A = csc_matrix(L, dtype=float, copy=True) - # Force A to be nonsingular. Since A is the Laplacian matrix of a - # connected graph, its rank deficiency is one, and thus one diagonal - # element needs to modified. Changing to infinity forces a zero in the - # corresponding element in the solution. - i = (A.indptr[1:] - A.indptr[:-1]).argmax() - A[i, i] = float('inf') - if method == 'tracemin_chol': - solver = _CholeskySolver(A) - else: - solver = _LUSolver(A) - else: - raise nx.NetworkXError('Unknown linear system solver: ' + method) - - # Initialize. - Lnorm = abs(L).sum(axis=1).flatten().max() - project(X) - W = asmatrix(ndarray(X.shape, order='F')) - - while True: - # Orthonormalize X. - X = qr(X)[0] - # Compute iteration matrix H. - W[:, :] = L * X - H = X.T * W - sigma, Y = eigh(H, overwrite_a=True) - # Compute the Ritz vectors. - X *= Y - # Test for convergence exploiting the fact that L * X == W * Y. - res = dasum(W * asmatrix(Y)[:, 0] - sigma[0] * X[:, 0]) / Lnorm - if res < tol: - break - # Compute X = L \ X / (X' * (L \ X)). - # L \ X can have an arbitrary projection on the nullspace of L, - # which will be eliminated. - W[:, :] = solver.solve(X, tol) - X = (inv(W.T * X) * W.T).T # Preserves Fortran storage order. - project(X) - - return sigma, asarray(X) - - -def _get_fiedler_func(method): - """Returns a function that solves the Fiedler eigenvalue problem. - """ - if method == "tracemin": # old style keyword <v2.1 - method = "tracemin_pcg" - if method in ("tracemin_pcg", "tracemin_chol", "tracemin_lu"): - def find_fiedler(L, x, normalized, tol, seed): - q = 1 if method == 'tracemin_pcg' else min(4, L.shape[0] - 1) - X = asmatrix(seed.normal(size=(q, L.shape[0]))).T - sigma, X = _tracemin_fiedler(L, X, normalized, tol, method) - return sigma[0], X[:, 0] - elif method == 'lanczos' or method == 'lobpcg': - def find_fiedler(L, x, normalized, tol, seed): - L = csc_matrix(L, dtype=float) - n = L.shape[0] - if normalized: - D = spdiags(1. / sqrt(L.diagonal()), [0], n, n, format='csc') - L = D * L * D - if method == 'lanczos' or n < 10: - # Avoid LOBPCG when n < 10 due to - # https://github.com/scipy/scipy/issues/3592 - # https://github.com/scipy/scipy/pull/3594 - sigma, X = eigsh(L, 2, which='SM', tol=tol, - return_eigenvectors=True) - return sigma[1], X[:, 1] - else: - X = asarray(asmatrix(x).T) - M = spdiags(1. / L.diagonal(), [0], n, n) - Y = ones(n) - if normalized: - Y /= D.diagonal() - sigma, X = lobpcg(L, X, M=M, Y=asmatrix(Y).T, tol=tol, - maxiter=n, largest=False) - return sigma[0], X[:, 0] - else: - raise nx.NetworkXError("unknown method '%s'." % method) - - return find_fiedler - - -@random_state(5) -@not_implemented_for('directed') -def algebraic_connectivity(G, weight='weight', normalized=False, tol=1e-8, - method='tracemin_pcg', seed=None): - """Returns the algebraic connectivity of an undirected graph. - - The algebraic connectivity of a connected undirected graph is the second - smallest eigenvalue of its Laplacian matrix. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - weight : object, optional (default: None) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_chol' Cholesky factorization - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness<randomness>`. - - Returns - ------- - algebraic_connectivity : float - Algebraic connectivity. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - NetworkXError - If G has less than two nodes. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - To use Cholesky factorization in the TraceMIN algorithm, the - :samp:`scikits.sparse` package must be installed. - - See Also - -------- - laplacian_matrix - """ - if len(G) < 2: - raise nx.NetworkXError('graph has less than two nodes.') - G = _preprocess_graph(G, weight) - if not nx.is_connected(G): - return 0. - - L = nx.laplacian_matrix(G) - if L.shape[0] == 2: - return 2. * L[0, 0] if not normalized else 2. - - find_fiedler = _get_fiedler_func(method) - x = None if method != 'lobpcg' else _rcm_estimate(G, G) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - return sigma - - -@random_state(5) -@not_implemented_for('directed') -def fiedler_vector(G, weight='weight', normalized=False, tol=1e-8, - method='tracemin_pcg', seed=None): - """Returns the Fiedler vector of a connected undirected graph. - - The Fiedler vector of a connected undirected graph is the eigenvector - corresponding to the second smallest eigenvalue of the Laplacian matrix of - of the graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - weight : object, optional (default: None) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_chol' Cholesky factorization - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness<randomness>`. - - Returns - ------- - fiedler_vector : NumPy array of floats. - Fiedler vector. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - NetworkXError - If G has less than two nodes or is not connected. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - To use Cholesky factorization in the TraceMIN algorithm, the - :samp:`scikits.sparse` package must be installed. - - See Also - -------- - laplacian_matrix - """ - if len(G) < 2: - raise nx.NetworkXError('graph has less than two nodes.') - G = _preprocess_graph(G, weight) - if not nx.is_connected(G): - raise nx.NetworkXError('graph is not connected.') - - if len(G) == 2: - return array([1., -1.]) - - find_fiedler = _get_fiedler_func(method) - L = nx.laplacian_matrix(G) - x = None if method != 'lobpcg' else _rcm_estimate(G, G) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - return fiedler - - -@random_state(5) -def spectral_ordering(G, weight='weight', normalized=False, tol=1e-8, - method='tracemin_pcg', seed=None): - """Compute the spectral_ordering of a graph. - - The spectral ordering of a graph is an ordering of its nodes where nodes - in the same weakly connected components appear contiguous and ordered by - their corresponding elements in the Fiedler vector of the component. - - Parameters - ---------- - G : NetworkX graph - A graph. - - weight : object, optional (default: None) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_chol' Cholesky factorization - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness<randomness>`. - - Returns - ------- - spectral_ordering : NumPy array of floats. - Spectral ordering of nodes. - - Raises - ------ - NetworkXError - If G is empty. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - To use Cholesky factorization in the TraceMIN algorithm, the - :samp:`scikits.sparse` package must be installed. - - See Also - -------- - laplacian_matrix - """ - if len(G) == 0: - raise nx.NetworkXError('graph is empty.') - G = _preprocess_graph(G, weight) - - find_fiedler = _get_fiedler_func(method) - order = [] - for component in nx.connected_components(G): - size = len(component) - if size > 2: - L = nx.laplacian_matrix(G, component) - x = None if method != 'lobpcg' else _rcm_estimate(G, component) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - sort_info = zip(fiedler, range(size), component) - order.extend(u for x, c, u in sorted(sort_info)) - else: - order.extend(component) - - return order - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy.sparse = pytest.importorskip('scipy.sparse')
