def distance_strength_of_connection(A, V, theta=2.0, relative_drop=True, cost=[0]): """ Distance based strength-of-connection Parameters ---------- A : csr_matrix or bsr_matrix Square, sparse matrix in CSR or BSR format V : array Coordinates of the vertices of the graph of A theta : float Drop tolerance of distance between points, see relative_drop relative_drop : bool If false, then a connection must be within a distance of theta from a point to be strongly connected. If true, then the closest connection is always strong, and other points must be within theta times the smallest distance to be strong Returns ------- C : csr_matrix C(i,j) = distance(point_i, point_j) Strength of connection matrix where strength values are distances, i.e. the smaller the value, the stronger the connection. Sparsity pattern of C is copied from A. Notes ----- - theta is a drop tolerance that is applied row-wise - If a BSR matrix given, then the return matrix is still CSR. The strength is given between super nodes based on the BSR block size. Examples -------- >>> from pyamg.gallery import load_example >>> from pyamg.strength import distance_strength_of_connection >>> data = load_example('airfoil') >>> A = data['A'].tocsr() >>> S = distance_strength_of_connection(data['A'], data['vertices']) """ # Amalgamate for the supernode case if sparse.isspmatrix_bsr(A): sn = int(A.shape[0] / A.blocksize[0]) u = np.ones((A.data.shape[0], )) A = sparse.csr_matrix((u, A.indices, A.indptr), shape=(sn, sn)) if not sparse.isspmatrix_csr(A): warn("Implicit conversion of A to csr", sparse.SparseEfficiencyWarning) A = sparse.csr_matrix(A) dim = V.shape[1] # Create two arrays for differencing the different coordinates such # that C(i,j) = distance(point_i, point_j) cols = A.indices rows = np.repeat(np.arange(A.shape[0]), A.indptr[1:] - A.indptr[0:-1]) # Insert difference for each coordinate into C C = (V[rows, 0] - V[cols, 0])**2 for d in range(1, dim): C += (V[rows, d] - V[cols, d])**2 C = np.sqrt(C) C[C < 1e-6] = 1e-6 C = sparse.csr_matrix((C, A.indices.copy(), A.indptr.copy()), shape=A.shape) # 2 len(rows) operations initially, 3 each loop iteration, # and one after --> 3*dim*len(rows) / A.nnz WUs = 3*dim WUs cost[0] += 3 * dim # Apply drop tolerance if relative_drop is True: if theta != np.inf: amg_core.apply_distance_filter(C.shape[0], theta, C.indptr, C.indices, C.data) cost[0] += float(2.0 * C.nnz) / A.nnz else: amg_core.apply_absolute_distance_filter(C.shape[0], theta, C.indptr, C.indices, C.data) cost[0] += float(C.nnz) / A.nnz C.eliminate_zeros() C = C + sparse.eye(C.shape[0], C.shape[1], format='csr') cost[0] += float(C.shape[0]) / A.nnz # Standardized strength values require small values be weak and large # values be strong. So, we invert the distances. C.data = 1.0 / C.data cost[0] += float(C.nnz) / A.nnz # Scale C by the largest magnitude entry in each row C = scale_rows_by_largest_entry(C) # Assume largest entry can be tracked in applying distance filter. # 1 WU to scale matrix. cost[0] += float(C.nnz) / A.nnz return C
def distance_strength_of_connection(A, V, theta=2.0, relative_drop=True): """ Distance based strength-of-connection Parameters ---------- A : csr_matrix or bsr_matrix Square, sparse matrix in CSR or BSR format V : array Coordinates of the vertices of the graph of A relative_drop : bool If false, then a connection must be within a distance of theta from a point to be strongly connected. If true, then the closest connection is always strong, and other points must be within theta times the smallest distance to be strong Returns ------- C : csr_matrix C(i,j) = distance(point_i, point_j) Strength of connection matrix where strength values are distances, i.e. the smaller the value, the stronger the connection. Sparsity pattern of C is copied from A. Notes ----- - theta is a drop tolerance that is applied row-wise - If a BSR matrix given, then the return matrix is still CSR. The strength is given between super nodes based on the BSR block size. Examples -------- >>> from pyamg.gallery import load_example >>> from pyamg.strength import distance_strength_of_connection >>> data = load_example('airfoil') >>> A = data['A'].tocsr() >>> S = distance_strength_of_connection(data['A'], data['vertices']) """ # Amalgamate for the supernode case if sparse.isspmatrix_bsr(A): sn = A.shape[0]/A.blocksize[0] u = np.ones((A.data.shape[0],)) A = sparse.csr_matrix((u, A.indices, A.indptr), shape=(sn, sn)) if not sparse.isspmatrix_csr(A): warn("Implicit conversion of A to csr", sparse.SparseEfficiencyWarning) A = sparse.csr_matrix(A) dim = V.shape[1] # Create two arrays for differencing the different coordinates such # that C(i,j) = distance(point_i, point_j) cols = A.indices rows = np.repeat(np.arange(A.shape[0]), A.indptr[1:] - A.indptr[0:-1]) # Insert difference for each coordinate into C C = (V[rows, 0] - V[cols, 0])**2 for d in range(1, dim): C += (V[rows, d] - V[cols, d])**2 C = np.sqrt(C) C[C < 1e-6] = 1e-6 C = sparse.csr_matrix((C, A.indices.copy(), A.indptr.copy()), shape=A.shape) # Apply drop tolerance if relative_drop is True: if theta != np.inf: amg_core.apply_distance_filter(C.shape[0], theta, C.indptr, C.indices, C.data) else: amg_core.apply_absolute_distance_filter(C.shape[0], theta, C.indptr, C.indices, C.data) C.eliminate_zeros() C = C + sparse.eye(C.shape[0], C.shape[1], format='csr') # Standardized strength values require small values be weak and large # values be strong. So, we invert the distances. C.data = 1.0/C.data # Scale C by the largest magnitude entry in each row C = scale_rows_by_largest_entry(C) return C