def init(self, data, attr, bpr_k=None, bpr_args=None, bpr_model=None): assert sp.isspmatrix_csr(data) assert sp.isspmatrix_csr(attr) self.data = data self.num_users, self.num_items = data.shape self.attr = attr assert attr.shape[0] >= self.num_items _, self.num_attrs = attr.shape if bpr_model==None: self.bpr_k = [self.num_users/5,bpr_k][bpr_k!=None] if bpr_args==None: self.bpr_args = bpr.BPRArgs(0.01, 1.0, 0.02125, 0.00355, 0.00355) else: self.bpr_args = bpr_args self.bpr_model = bpr.BPR(self.bpr_k, self.bpr_args) else: self.bpr_model = bpr_model self.bpr_k = bpr_model.D self.bpr_args = bpr.BPRArgs(bpr_model.learning_rate, \ bpr_model.bias_regularization, \ bpr_model.user_regularization, \ bpr_model.positive_item_regularization, \ bpr_model.negative_item_regularization, \ bpr_model.update_negative_item_factors) sample_negative_items_empirically = False self.sampler = bpr.UniformUserUniformItem(sample_negative_items_empirically)
def testQobjData(self): N=10 data1=random.random((N,N))+1j*random.random((N,N))-(0.5+0.5j) q1=Qobj(data1) #check if data is a csr_matrix if originally array self.assertTrue(sp.isspmatrix_csr(q1.data)) #check if dense ouput is equal to original data self.assertTrue(all(q1.data.todense()-matrix(data1))==0) data2=random.random((N,N))+1j*random.random((N,N))-(0.5+0.5j) data2=sp.csr_matrix(data2) q2=Qobj(data2) #check if data is a csr_matrix if originally csr_matrix self.assertTrue(sp.isspmatrix_csr(q2.data)) data3=1 q3=Qobj(data3) #check if data is a csr_matrix if originally int self.assertTrue(sp.isspmatrix_csr(q3.data)) data4=random.random((N,N))+1j*random.random((N,N))-(0.5+0.5j) data4=matrix(data4) q4=Qobj(data4) #check if data is a csr_matrix if originally csr_matrix self.assertTrue(sp.isspmatrix_csr(q4.data)) self.assertTrue(all(q4.data.todense()-matrix(data4))==0)
def test_QobjData(): "Qobj data" N = 10 data1 = np.random.random( (N, N)) + 1j * np.random.random((N, N)) - (0.5 + 0.5j) q1 = Qobj(data1) # check if data is a csr_matrix if originally array assert_equal(sp.isspmatrix_csr(q1.data), True) # check if dense ouput is equal to original data assert_(np.all(q1.data.todense() - np.matrix(data1) == 0)) data2 = np.random.random( (N, N)) + 1j * np.random.random((N, N)) - (0.5 + 0.5j) data2 = sp.csr_matrix(data2) q2 = Qobj(data2) # check if data is a csr_matrix if originally csr_matrix assert_equal(sp.isspmatrix_csr(q2.data), True) data3 = 1 q3 = Qobj(data3) # check if data is a csr_matrix if originally int assert_equal(sp.isspmatrix_csr(q3.data), True) data4 = np.random.random( (N, N)) + 1j * np.random.random((N, N)) - (0.5 + 0.5j) data4 = np.matrix(data4) q4 = Qobj(data4) # check if data is a csr_matrix if originally csr_matrix assert_equal(sp.isspmatrix_csr(q4.data), True) assert_(np.all(q4.data.todense() - np.matrix(data4) == 0))
def zcsr_kron(A,B): """Kronecker product between two CSR format sparse matrices with dtype = complex. Parameters ---------- A : csr_matrix Input matrix B : csr_matrix Input matrix Returns ------- C : csr_matrix Kronecker product of A & B """ if (not sp.isspmatrix_csr(A)) or (not sp.isspmatrix_csr(B)): raise TypeError('Both input sparse matrices must be in CSR format.') if (not A.dtype == complex) or (not B.dtype == complex): raise TypeError('Both input sparse matrices must have dtype=complex.') C = _csr_kron(A.data, A.indices, A.indptr, A.shape[0], A.shape[1], B.data, B.indices, B.indptr, B.shape[0], B.shape[1]) return C
def Gradient(hmesh,hraster,qvec,mvec,mua,mus,ref,freq,data,sd): if sparse.isspmatrix_csr(qvec)==True: qvec = sparse.csc_matrix(qvec) if sparse.isspmatrix_csr(mvec)==True: mvec = sparse.csc_matrix(mvec) return toastmod.Gradient(hmesh,hraster,qvec.data,qvec.indptr,qvec.indices,mvec.data,mvec.indptr,mvec.indices,mua,mus,ref,freq,data,sd)
def __init__(self, datamat, attrmat, k): assert sp.isspmatrix_csr(datamat) assert sp.isspmatrix_csr(attrmat) self.datamat = datamat.tocsc() self.attrmat = attrmat self.k = k _, self.num_items = datamat.shape self.index = [i for i in range(self.num_items)] random.shuffle(self.index)
def spsolve(A, b, permc_spec=None, use_umfpack=True): """Solve the sparse linear system Ax=b """ if isspmatrix( b ): b = b.toarray() if b.ndim > 1: if max( b.shape ) == b.size: b = b.squeeze() else: raise ValueError("rhs must be a vector (has shape %s)" % (b.shape,)) if not (isspmatrix_csc(A) or isspmatrix_csr(A)): A = csc_matrix(A) warn('spsolve requires CSC or CSR matrix format', SparseEfficiencyWarning) A.sort_indices() A = A.asfptype() #upcast to a floating point format M, N = A.shape if (M != N): raise ValueError("matrix must be square (has shape %s)" % ((M, N),)) if M != b.size: raise ValueError("matrix - rhs size mismatch (%s - %s)" % (A.shape, b.size)) use_umfpack = use_umfpack and useUmfpack if isUmfpack and use_umfpack: if noScikit: warn( 'scipy.sparse.linalg.dsolve.umfpack will be removed,' ' install scikits.umfpack instead', DeprecationWarning ) if A.dtype.char not in 'dD': raise ValueError("convert matrix data to double, please, using" " .astype(), or set linsolve.useUmfpack = False") b = asarray(b, dtype=A.dtype).reshape(-1) family = {'d' : 'di', 'D' : 'zi'} umf = umfpack.UmfpackContext( family[A.dtype.char] ) return umf.linsolve( umfpack.UMFPACK_A, A, b, autoTranspose = True ) else: if isspmatrix_csc(A): flag = 1 # CSC format elif isspmatrix_csr(A): flag = 0 # CSR format else: A = csc_matrix(A) flag = 1 b = asarray(b, dtype=A.dtype) options = dict(ColPerm=permc_spec) return _superlu.gssv(N, A.nnz, A.data, A.indices, A.indptr, b, flag, options=options)[0]
def f_relaxation(A, x, b, splitting, iterations=1, sweep='forward'): """Perform gauss-seidel f-relaxation iteration on the linear system Ax=b Parameters ---------- A : {csr_matrix, bsr_matrix} Sparse NxN matrix x : ndarray Approximate solution (length N) b : ndarray Right-hand side (length N) splitting : ndarray CF splitting, 1 = C-pt, 0 = f-pt, relaxation is only performed on f-pts iterations : int Number of iterations to perform sweep : {'forward','backward','symmetric'} Direction of sweep Returns ------- Nothing, x will be modified in place. """ A, x, b = make_system(A, x, b, formats=['csr']) if sparse.isspmatrix_csr(A): blocksize = 1 else: R, C = A.blocksize if R != C: raise ValueError('BSR blocks must be square') blocksize = R if sweep == 'forward': row_start, row_stop, row_step = 0, int(len(x)/blocksize), 1 elif sweep == 'backward': row_start, row_stop, row_step = int(len(x)/blocksize)-1, -1, -1 elif sweep == 'symmetric': for iter in range(iterations): f_relaxation(A, x, b, splitting, iterations=1, sweep='forward') f_relaxation(A, x, b, splitting, iterations=1, sweep='backward') return else: raise ValueError("valid sweep directions are 'forward',\ 'backward', and 'symmetric'") if sparse.isspmatrix_csr(A): for iter in range(iterations): amg_core.f_relaxation(A.indptr, A.indices, A.data, x, b, splitting, row_start, row_stop, row_step) else: print("Expected csr matrix for f-relaxation")
def csrmm(a, b, c, transA=False, transB=False, alpha=1.0, beta=0.0): assert a.dtype == b.dtype if len(a.shape) < 2: a = a.reshape(1, a.shape[0]) if len(b.shape) < 2: b = b.reshape(1, b.shape[0]) m, k = b.shape if transB else (b.shape[1], b.shape[0]) l, n = a.shape if transA else (a.shape[1], a.shape[0]) assert c.shape == (n, m) and c.dtype == a.dtype assert a.dtype == np.float32 and b.dtype == np.float32 assert c.flags.c_contiguous if a.dtype == np.float32: alpha = np.float32(alpha) beta = np.float32(beta) elif a.dtype == np.float64: alpha = np.float64(alpha) beta = np.float64(beta) if sparse.isspmatrix_csr(a): ldb = b.shape[1] ta = 't'.encode("ascii") if transA else 'n'.encode("ascii") m, k = a.shape if not transB: l, n = b.shape ldc = c.shape[1] __csrmm_impl(a, b, c, m, k, n, ldb, ldc, alpha, beta, ta, False) else: n, l = b.shape tmp = c.astype(dtype=c.dtype, order="f") ldc = c.shape[0] __csrmm_impl(a, b, tmp, m, k, n, ldb, ldc, alpha, beta, ta, True) c[:] = tmp[:] elif sparse.isspmatrix_csr(b): # MKL offers only Y += op(B)*A (with B sparse) # but our call is Y += op(A)*op(B) (with B sparse) # We will use calculate (op(B)^T*op(A)^T)^T, using the fortran ("one-based") # version of the call. Since Y is row-major, we can ignore the outer # transpose. We will have to transpose A manually, though assert not sparse.issparse(a) if transA: a = a.astype(dtype=np.float32, order='F') # transpose a m, k = b.shape l, n = a.shape if transA else (a.shape[1], a.shape[0]) ldb = l ldc = c.shape[1] ta = 'n'.encode("ascii") if transB else 't'.encode("ascii") __csrmm_impl(b, a, c, m, k, n, ldb, ldc, alpha, beta, ta, True) return c
def inverse_transform(self, X, copy=None): """Scale back the data to the original representation Parameters ---------- X : array-like with shape [n_samples, n_features] The data used to scale along the features axis. """ copy = copy if copy is not None else self.copy if sparse.issparse(X): if self.with_mean: raise ValueError( "Cannot uncenter sparse matrices: pass `with_mean=False` " "instead See docstring for motivation and alternatives.") if not sparse.isspmatrix_csr(X): X = X.tocsr() copy = False if copy: X = X.copy() if self.std_ is not None: inplace_column_scale(X, self.std_) else: X = np.asarray(X) if copy: X = X.copy() if self.with_std: X *= self.std_ if self.with_mean: X += self.mean_ return X
def sp_profile(A): """Returns the total, lower, and upper profiles of a sparse matrix. If the matrix is symmetric then the upper and lower profiles are identical. Diagonal matrices have zero profile. Parameters ---------- A : csr_matrix, csc_matrix Input matrix """ if sp.isspmatrix_csr(A): up = _sparse_profile(A.indices, A.indptr, A.shape[0]) A = A.tocsc() lp = _sparse_profile(A.indices, A.indptr, A.shape[0]) elif sp.isspmatrix_csc(A): lp = _sparse_profile(A.indices, A.indptr, A.shape[0]) A = A.tocsr() up = _sparse_profile(A.indices, A.indptr, A.shape[0]) else: raise TypeError('Input sparse matrix must be in CSR or CSC format.') return up+lp, lp, up
def transform(self, X, y=None, copy=None): """Perform standardization by centering and scaling Parameters ---------- X : array-like with shape [n_samples, n_features] The data used to scale along the features axis. """ copy = copy if copy is not None else self.copy if sp.issparse(X): if self.with_mean: raise ValueError( "Cannot center sparse matrices: pass `with_mean=False` " "instead See docstring for motivation and alternatives.") warn_if_not_float(X, estimator=self) if not sp.isspmatrix_csr(X): X = X.tocsr() copy = False if copy: X = X.copy() inplace_csr_column_scale(X, 1 / self.std_) else: X = np.asarray(X) warn_if_not_float(X, estimator=self) if copy: X = X.copy() if self.with_mean: X -= self.mean_ if self.with_std: X /= self.std_ return X
def fit(self, X, y=None): """Compute the mean and std to be used for later scaling. Parameters ---------- X : array-like or CSR matrix with shape [n_samples, n_features] The data used to compute the mean and standard deviation used for later scaling along the features axis. """ if sp.issparse(X): if self.with_mean: raise ValueError( "Cannot center sparse matrices: pass `with_mean=False` " "instead See docstring for motivation and alternatives.") warn_if_not_float(X, estimator=self) copy = self.copy if not sp.isspmatrix_csr(X): X = X.tocsr() copy = False if copy: X = X.copy() self.mean_ = None _, var = mean_variance_axis0(X) self.std_ = np.sqrt(var) self.std_[var == 0.0] = 1.0 return self else: X = np.asarray(X) warn_if_not_float(X, estimator=self) self.mean_, self.std_ = _mean_and_std( X, axis=0, with_mean=self.with_mean, with_std=self.with_std) return self
def sparseScalarProductOfDot (A, B, C, out=None): ''' Returns A * np.dot(B, C), however it does so keeping in mind the sparsity of A, calculating values only where required. Params A - a sparse CSR matrix B - a dense matrix C - a dense matrix out - if specified, must be a sparse CSR matrix with identical non-zero pattern to A (i.e. same indices and indptr) Returns out_data, though note that this is the same parameter passed in and overwitten. ''' assert ssp.isspmatrix_csr(A), "A matrix is not a CSR matrix" assert not np.isfortran(B), "B matrix is not stored in row-major form" assert not np.isfortran(C), "C matrix is not stored in row-major form" if out is None: out = A.copy() if A.dtype == np.float64: compiled.sparseScalarProductOfDot_f8(A.data, A.indices, A.indptr, B, C, out.data) elif A.dtype == np.float32: compiled.sparseScalarProductOfDot_f4(A.data, A.indices, A.indptr, B, C, out.data) else: _sparseScalarProductOfDot_py(A,B,C, out) return out
def _getIndx(self, mtx): if sp.isspmatrix_csc(mtx): indx = mtx.indices self.isCSR = 0 elif sp.isspmatrix_csr(mtx): indx = mtx.indices self.isCSR = 1 else: raise TypeError('must be a CSC/CSR matrix (is %s)' % mtx.__class__) ## # Should check types of indices to correspond to familyTypes. if self.family[1] == 'i': if (indx.dtype != np.dtype('i')) \ or mtx.indptr.dtype != np.dtype('i'): raise ValueError('matrix must have int indices') else: if (indx.dtype != np.dtype('l')) \ or mtx.indptr.dtype != np.dtype('l'): raise ValueError('matrix must have long indices') if self.isReal: if mtx.data.dtype != np.dtype('f8'): raise ValueError('matrix must have float64 values') else: if mtx.data.dtype != np.dtype('c16'): raise ValueError('matrix must have complex128 values') return indx
def __init__(self, A): if not (isspmatrix_csc(A) or isspmatrix_csr(A)): A = csc_matrix(A) warn('spsolve requires A be CSC or CSR matrix format', SparseEfficiencyWarning) A.sort_indices() A = A.asfptype() # upcast to a floating point format M, N = A.shape if (M != N): raise ValueError("matrix must be square (has shape %s)" % ((M, N),)) f_type = np.sctypeDict[A.dtype.name] i_type = np.sctypeDict[A.indices.dtype.name] try: family = _families[(f_type, i_type)] except KeyError: msg = 'only float64 or complex128 matrices with int32 or int64' \ ' indices are supported! (got: matrix: %s, indices: %s)' \ % (f_type, i_type) raise ValueError(msg) self.umf = UmfpackContext(family) self.umf.numeric(A) self._A = A self._L = None self._U = None self._P = None self._Q = None self._R = None
def sparseScalarQuotientOfNormedDot (A, B, C, d, out=None): ''' Returns A / np.dot(B, C/D), however it does so keeping in mind the sparsity of A, calculating values only where required. Params A - a sparse CSR matrix B - a dense matrix C - a dense matrix d - a dense vector whose dimensionality matches the column-count of C out - if specified, must be a sparse CSR matrix with identical non-zero pattern to A (i.e. same indices and indptr) Returns out_data, though note that this is the same parameter passed in and overwitten. ''' assert ssp.isspmatrix_csr(A), "A matrix is not a CSR matrix" assert not np.isfortran(B), "B matrix is not stored in row-major form" assert not np.isfortran(C), "C matrix is not stored in row-major form" if out is None: out = A.copy() if A.dtype == np.float64: compiled.sparseScalarQuotientOfNormedDot_f8(A.data, A.indices, A.indptr, B, C, d, out.data) elif A.dtype == np.float32: compiled.sparseScalarQuotientOfNormedDot_f4(A.data, A.indices, A.indptr, B, C, d, out.data) else: raise ValueError ("No implementation for the datatype " + str(A.dtype)) return out
def chooseNext(self, pool, X=None, model=None, k=1, current_train_indices = None, current_train_y = None): if not self.sub_pool: rand_indices = self.randgen.permutation(len(pool)) array_pool = np.array(list(pool)) candidates = array_pool[rand_indices[:self.sub_pool]] print candidates else: candidates = list(pool) if ss.issparse(X): if not ss.isspmatrix_csr(X): X = X.tocsr() probs = model.predict_proba(X[candidates]) probs_positive = probs[:,1] EGL_list = [] for i in range(len(candidates)): positive = self.positive_function(probs_positive[i], X[candidates[i]]) negative = self.negative_function(probs_positive[i], X[candidates[i]]) EGL_i = self.Expected_Euclidean_Norm(positive, negative, probs_positive[i]) EGL_list.append(EGL_i) ranked = np.argsort(EGL_list)[::-1] chosen = [candidates[j] for j in ranked[:k]] return chosen
def breadth_first_search(A, start): """ Breadth-First-Search (BFS) of a graph in CSR or CSC matrix format starting from a given node (row). Takes Qobjs and CSR or CSC matrices as inputs. This function requires a matrix with symmetric structure. Use A+trans(A) if original matrix is not symmetric or not sure. Parameters ---------- A : csc_matrix, csr_matrix Input graph in CSC or CSR matrix format start : int Staring node for BFS traversal. Returns ------- order : array Order in which nodes are traversed from starting node. levels : array Level of the nodes in the order that they are traversed. """ if not (sp.isspmatrix_csc(A) or sp.isspmatrix_csr(A)): raise TypeError('Input must be CSC or CSR sparse matrix.') num_rows = A.shape[0] start = int(start) order, levels = _breadth_first_search(A.indices, A.indptr, num_rows, start) # since maybe not all nodes are in search, check for unused entires in # arrays return order[order != -1], levels[levels != -1]
def filter_high_counts(X, lengths=None, percentage=0.02, copy=True): """ Filter rows and columns with high counts Parameters ---------- X : ndarray (n, n) Count matrix (hollow, symetric) lengths : ndarray (m, ), optional, default: None Lengths of the chromosomes percentage : float, optional, default: 0.02 percentage of rows and columns to discard copy : boolean, optional, default: True If set to true, copies the count matrix Return ------ X : ndarray (n, n) The filtered array Notes ----- New in 0.6 """ if sparse.issparse(X): if not sparse.isspmatrix_csr(X): X = X.tocsr() X.sort_indices() else: X[np.isnan(X)] = 0 return _filter_high_sum(X, percentage=percentage)
def __init__(self, A): if not (isspmatrix_csc(A) or isspmatrix_csr(A)): A = csc_matrix(A) warn('spsolve requires A be CSC or CSR matrix format', SparseEfficiencyWarning) A.sort_indices() A = A.asfptype() # upcast to a floating point format M, N = A.shape if (M != N): raise ValueError("matrix must be square (has shape %s)" % ((M, N),)) if A.dtype.char not in 'dD': raise ValueError("Only double precision matrices supported") family = {'d': 'di', 'D': 'zi'} self.umf = UmfpackContext(family[A.dtype.char]) self.umf.numeric(A) self._A = A self._L = None self._U = None self._P = None self._Q = None self._R = None
def chooseNext(self, pool, X=None, model=None, k=1, current_train_indices = None, current_train_y = None): """Overide method BaseStrategy.chooseNext **Parameters** * pool (*int*) - range of numbers within length of pool * X - None or pool.toarray() * model - None * k (*int*) - 1 or step size * current_train_indices - None or array of trained indices * current_train_y - None or train_indices specific to y_pool **Returns** * [candidates[i] for i in uis[:k]]""" if not self.sub_pool: rand_indices = self.randgen.permutation(len(pool)) array_pool = np.array(list(pool)) candidates = array_pool[rand_indices[:self.sub_pool]] else: candidates = list(pool) if ss.issparse(X): if not ss.isspmatrix_csr(X): X = X.tocsr() probs = model.predict_proba(X[candidates]) uncerts = np.min(probs, axis=1) uis = np.argsort(uncerts)[::-1] chosen = [candidates[i] for i in uis[:k]] return chosen
def _sparse_probs(self, data): probs = self._priors(data) n_vals = max(p.shape[1] for p in self.log_cont_prob) + 1 log_prob = np.zeros((len(self.log_cont_prob), n_vals, self.log_cont_prob[0].shape[0])) for i, p in enumerate(self.log_cont_prob): p0 = p.T[0].copy() probs[:] += p0 log_prob[i, :p.shape[1]] = p.T - p0 dat = data.data.copy() dat[np.isnan(dat)] = n_vals - 1 dat = dat.astype(int) if sp.isspmatrix_csr(data): for row, start, end in zip(probs, data.indptr, data.indptr[1:]): row += log_prob[data.indices[start:end], dat[start:end]].sum(axis=0) else: csc = data.tocsc() for start, end, attr_prob in zip(csc.indptr, csc.indptr[1:], log_prob): probs[csc.indices[start:end]] += attr_prob[dat[start:end]] return probs
def scale(X, axis=0, with_mean=True, with_std=True, copy=True): """ Adopted from scikit learn, scale data vector to zero mean and unit variance.""" if scs.issparse(X): if with_mean: raise ValueError( "Cannot center sparse matrices: pass `with_mean=False` instead" " See docstring for motivation and alternatives.") if axis != 0: raise ValueError("Can only scale sparse matrix on axis=0, " " got axis=%d" % axis) if not scs.isspmatrix_csr(X): X = X.tocsr() copy = False if copy: X = X.copy() _, var = mean_variance_axis(X, axis=0) var[var == 0.0] = 1.0 inplace_column_scale(X, 1 / np.sqrt(var)) else: X = np.asarray(X) mean_, std_ = _mean_and_std( X, axis, with_mean=with_mean, with_std=with_std) if copy: X = X.copy() # Xr is a view on the original array that enables easy use of # broadcasting on the axis in which we are interested in Xr = np.rollaxis(X, axis) if with_mean: Xr -= mean_ mean_1 = Xr.mean(axis=0) # Verify that mean_1 is 'close to zero'. If X contains very # large values, mean_1 can also be very large, due to a lack of # precision of mean_. In this case, a pre-scaling of the # concerned feature is efficient, for instance by its mean or # maximum. if not np.allclose(mean_1, 0): warnings.warn("Numerical issues were encountered " "when centering the data " "and might not be solved. Dataset may " "contain too large values. You may need " "to prescale your features.") Xr -= mean_1 if with_std: Xr /= std_ if with_mean: mean_2 = Xr.mean(axis=0) # If mean_2 is not 'close to zero', it comes from the fact that # std_ is very small so that mean_2 = mean_1/std_ > 0, even if # mean_1 was close to zero. The problem is thus essentially due # to the lack of precision of mean_. A solution is then to # substract the mean again: if not np.allclose(mean_2, 0): warnings.warn("Numerical issues were encountered " "when scaling the data " "and might not be solved. The standard " "deviation of the data is probably " "very close to 0. ") Xr -= mean_2 return X
def save_group(h5file, name, mat): if not ssp.isspmatrix_csr(mat): mat = mat.tocsr() tosaveg = h5file.create_group(name) tosaveg.create_dataset("indptr",data=mat.indptr,compression='lzf') tosaveg.create_dataset("data",data=mat.data,compression='lzf') tosaveg.create_dataset("indices",data=mat.indices,compression='lzf')
def transform(self, X): """ Scale a matrix according to the previously computed std weights, using a sparse implementation. Parameters ---------- X : array-like, shape [n_samples, n_features] Input data that will be transformed. Supports sparse input. Attributes ---------- weight_ : ndarray, shape (n_features,) Column-wise standard deviations. Returns ---------- X = array-like, shape [n_samples, n_features] The scaled input data in sparse format. """ if not sp.isspmatrix_csr(X): # convert to sparse format if needed: X = sp.csr_matrix(X, dtype=np.float64) for i in range(X.shape[0]): start, end = X.indptr[i], X.indptr[i+1] X.data[start:end] /= self.weights_[X.indices[start:end]] return X
def _to_csr(self, X): if (sparse.isspmatrix_csr(X)): return X elif (sparse.issparse(X)): return X.tocsr() else: # i.e. numpy arrays/ndmatrices return sparse.csr_matrix(X)
def transform(self, X): """ Scale a matrix according to the previously computed std weights, using a sparse implementation. Parameters ---------- X : array-like, shape [n_samples, n_features] Input data that will be transformed. Supports sparse input (i.e. will return a sparse matrix if X is sparse). Attributes ---------- weight_ : ndarray, shape (n_features,) Column-wise standard deviations. Returns ---------- X = array-like, shape [n_samples, n_features] The scaled input data in sparse format. """ if sp.isspmatrix_csr(X): X = X.toarray() X /= self.weights_ return sp.csr_matrix(X) else: X /= self.weights_ return X
def getTransitionMatrix(self,probabilities=True): """ If self.P has been given already, we will reuse it and convert it to a sparse csr matrix if needed. Otherwise, we will generate it using the direct or indirect method. Since most solution methods use stochastic matrices, by default we return a probability matrix. By setting probabilities=False we can also return a rate matrix. """ if self.P is not None: if isspmatrix(self.P): if not isspmatrix_csr(self.P): self.P = self.P.tocsr() else: assert isinstance(self.P, np.ndarray) and self.P.ndim==2 and self.P.shape[0]==self.P.shape[1],'P needs to be a 2d numpy array with an equal number of columns and rows' self.P = csr_matrix(self.P) elif self.direct == True: self.P = self.directInitialMatrix() else: self.P = self.indirectInitialMatrix(self.initialState) if probabilities: P = self.convertToProbabilityMatrix(self.P) else: P = self.convertToRateMatrix(self.P) self.assertSingleClass(P) return P
def test_num_type(): "Operator CSR Type: num" op = num(5) assert_equal(isspmatrix_csr(op.data), True)
def test_doc_level_tf_idf_type(): d = Doc("Ali topu tut. Ömer ılık süt iç.") assert isspmatrix_csr(d.tfidf_matrix)
def energy_based_strength_of_connection(A, theta=0.0, k=2): """Energy Strength Measure. Compute a strength of connection matrix using an energy-based measure. Parameters ---------- A : sparse-matrix matrix from which to generate strength of connection information theta : float Threshold parameter in [0,1] k : int Number of relaxation steps used to generate strength information Returns ------- S : csr_matrix Matrix graph defining strong connections. The sparsity pattern of S matches that of A. For BSR matrices, S is a reduced strength of connection matrix that describes connections between supernodes. Notes ----- This method relaxes with weighted-Jacobi in order to approximate the matrix inverse. A normalized change of energy is then used to define point-wise strength of connection values. Specifically, let v be the approximation to the i-th column of the inverse, then (S_ij)^2 = <v_j, v_j>_A / <v, v>_A, where v_j = v, such that entry j in v has been zeroed out. As is common, larger values imply a stronger connection. Current implementation is a very slow pure-python implementation for experimental purposes, only. See [2006BrBrMaMaMc]_ for more details. References ---------- .. [2006BrBrMaMaMc] Brannick, Brezina, MacLachlan, Manteuffel, McCormick. "An Energy-Based AMG Coarsening Strategy", Numerical Linear Algebra with Applications, vol. 13, pp. 133-148, 2006. Examples -------- >>> import numpy as np >>> from pyamg.gallery import stencil_grid >>> from pyamg.strength import energy_based_strength_of_connection >>> n=3 >>> stencil = np.array([[-1.0,-1.0,-1.0], ... [-1.0, 8.0,-1.0], ... [-1.0,-1.0,-1.0]]) >>> A = stencil_grid(stencil, (n,n), format='csr') >>> S = energy_based_strength_of_connection(A, 0.0) """ if theta < 0: raise ValueError('expected a positive theta') if not sparse.isspmatrix(A): raise ValueError('expected sparse matrix') if k < 0: raise ValueError('expected positive number of steps') if not isinstance(k, int): raise ValueError('expected integer') if sparse.isspmatrix_bsr(A): bsr_flag = True numPDEs = A.blocksize[0] if A.blocksize[0] != A.blocksize[1]: raise ValueError('expected square blocks in BSR matrix A') else: bsr_flag = False # Convert A to csc and Atilde to csr if sparse.isspmatrix_csr(A): Atilde = A.copy() A = A.tocsc() else: A = A.tocsc() Atilde = A.copy() Atilde = Atilde.tocsr() # Calculate the weighted-Jacobi parameter D = A.diagonal() Dinv = 1.0 / D Dinv[D == 0] = 0.0 Dinv = sparse.csc_matrix( (Dinv, (np.arange(A.shape[0]), np.arange(A.shape[1]))), shape=A.shape) DinvA = Dinv * A omega = 1.0 / approximate_spectral_radius(DinvA) del DinvA # Approximate A-inverse with k steps of w-Jacobi and a zero initial guess S = sparse.csc_matrix(A.shape, dtype=A.dtype) # empty matrix Id = sparse.eye(A.shape[0], A.shape[1], format='csc') for _i in range(k + 1): S = S + omega * (Dinv * (Id - A * S)) # Calculate the strength entries in S column-wise, but only strength # values at the sparsity pattern of A for i in range(Atilde.shape[0]): v = S[:, i].toarray() v = v.ravel() Av = A @ v denom = np.sqrt(np.inner(v.conj(), Av)) # replace entries in row i with strength values for j in range(Atilde.indptr[i], Atilde.indptr[i + 1]): col = Atilde.indices[j] vj = v[col].copy() v[col] = 0.0 # = (||v_j||_A - ||v||_A) / ||v||_A val = np.sqrt(np.inner(v.conj(), A @ v)) / denom - 1.0 # Negative values generally imply a weak connection if val > -0.01: Atilde.data[j] = abs(val) else: Atilde.data[j] = 0.0 v[col] = vj # Apply drop tolerance Atilde = classical_strength_of_connection(Atilde, theta=theta) Atilde.eliminate_zeros() # Put ones on the diagonal Atilde = Atilde + Id.tocsr() Atilde.sort_indices() # Amalgamate Atilde for the BSR case, using ones for all strong connections if bsr_flag: Atilde = Atilde.tobsr(blocksize=(numPDEs, numPDEs)) nblocks = Atilde.indices.shape[0] uone = np.ones((nblocks, )) Atilde = sparse.csr_matrix((uone, Atilde.indices, Atilde.indptr), shape=(int(Atilde.shape[0] / numPDEs), int(Atilde.shape[1] / numPDEs))) # Scale C by the largest magnitude entry in each row Atilde = scale_rows_by_largest_entry(Atilde) return Atilde
def algebraic_distance(A, alpha=0.5, R=5, k=20, epsilon=2.0, p=2): """Algebraic Distance Strength Measure. Parameters ---------- A : csr_matrix Sparse NxN matrix alpha : scalar Weight for Jacobi R : integer Number of random vectors k : integer Number of relaxation passes epsilon : scalar Drop tolerance p : scalar or inf p-norm of the measure Returns ------- C : csr_matrix Sparse matrix of strength values References ---------- .. [SaSaSc] Ilya Safro, Peter Sanders, and Christian Schulz, "Advanced Coarsening Schemes for Graph Partitioning" Notes ----- No unit testing yet. Does not handle BSR matrices yet. See [SaSaSc]_ for more details. """ if not sparse.isspmatrix_csr(A): A = sparse.csr_matrix(A) if alpha < 0: raise ValueError('expected alpha>0') if R <= 0 or not isinstance(R, int): raise ValueError('expected integer R>0') if k <= 0 or not isinstance(k, int): raise ValueError('expected integer k>0') if epsilon < 1: raise ValueError('expected epsilon>1.0') if p < 1: raise ValueError('expected p>1 or equal to numpy.inf') def distance(x): (rows, cols) = A.nonzero() if p != np.inf: avg = np.sum(np.abs(x[rows] - x[cols])**p, axis=1) / R return (avg)**(1.0 / p) return np.abs(x[rows] - x[cols]).max(axis=1) return distance_measure_common(A, distance, alpha, R, k, epsilon)
def gauss_seidel(A, x, b, iterations=1, sweep='forward'): """Perform Gauss-Seidel iteration on the linear system Ax=b Parameters ---------- A : {csr_matrix, bsr_matrix} Sparse NxN matrix x : ndarray Approximate solution (length N) b : ndarray Right-hand side (length N) iterations : int Number of iterations to perform sweep : {'forward','backward','symmetric'} Direction of sweep Returns ------- Nothing, x will be modified in place. Examples -------- >>> # Use Gauss-Seidel as a Stand-Alone Solver >>> from pyamg.relaxation.relaxation import gauss_seidel >>> from pyamg.gallery import poisson >>> from pyamg.util.linalg import norm >>> import numpy as np >>> A = poisson((10,10), format='csr') >>> x0 = np.zeros((A.shape[0],1)) >>> b = np.ones((A.shape[0],1)) >>> gauss_seidel(A, x0, b, iterations=10) >>> print norm(b-A*x0) 4.00733716236 >>> # >>> # Use Gauss-Seidel as the Multigrid Smoother >>> from pyamg import smoothed_aggregation_solver >>> sa = smoothed_aggregation_solver(A, B=np.ones((A.shape[0],1)), ... coarse_solver='pinv2', max_coarse=50, ... presmoother=('gauss_seidel', {'sweep':'symmetric'}), ... postsmoother=('gauss_seidel', {'sweep':'symmetric'})) >>> x0=np.zeros((A.shape[0],1)) >>> residuals=[] >>> x = sa.solve(b, x0=x0, tol=1e-8, residuals=residuals) """ A, x, b = make_system(A, x, b, formats=['csr', 'bsr']) if sparse.isspmatrix_csr(A): blocksize = 1 else: R, C = A.blocksize if R != C: raise ValueError('BSR blocks must be square') blocksize = R if sweep == 'forward': row_start, row_stop, row_step = 0, int(len(x) / blocksize), 1 elif sweep == 'backward': row_start, row_stop, row_step = int(len(x) / blocksize) - 1, -1, -1 elif sweep == 'symmetric': for iter in range(iterations): gauss_seidel(A, x, b, iterations=1, sweep='forward') gauss_seidel(A, x, b, iterations=1, sweep='backward') return else: raise ValueError("valid sweep directions are 'forward',\ 'backward', and 'symmetric'") if sparse.isspmatrix_csr(A): for iter in range(iterations): amg_core.gauss_seidel(A.indptr, A.indices, A.data, x, b, row_start, row_stop, row_step) else: for iter in range(iterations): amg_core.bsr_gauss_seidel(A.indptr, A.indices, np.ravel(A.data), x, b, row_start, row_stop, row_step, R)
def rootnode_solver(A, B=None, BH=None, symmetry='hermitian', strength='symmetric', aggregate='standard', smooth='energy', presmoother=('block_gauss_seidel', { 'sweep': 'symmetric' }), postsmoother=('block_gauss_seidel', { 'sweep': 'symmetric' }), improve_candidates=('block_gauss_seidel', { 'sweep': 'symmetric', 'iterations': 4 }), max_levels=10, max_coarse=10, diagonal_dominance=False, keep=False, **kwargs): """ Create a multilevel solver using root-node based Smoothed Aggregation (SA). See the notes below, for the major differences with the classical-style smoothed aggregation solver in aggregation.smoothed_aggregation_solver. Parameters ---------- A : csr_matrix, bsr_matrix Sparse NxN matrix in CSR or BSR format B : None, array_like Right near-nullspace candidates stored in the columns of an NxK array. K must be >= the blocksize of A (see reference [2011OlScTu]_). The default value B=None is equivalent to choosing the constant over each block-variable, B=np.kron(np.ones((A.shape[0]/blocksize(A), 1)), np.eye(blocksize(A))) BH : None, array_like Left near-nullspace candidates stored in the columns of an NxK array. BH is only used if symmetry is 'nonsymmetric'. K must be >= the blocksize of A (see reference [2011OlScTu]_). The default value B=None is equivalent to choosing the constant over each block-variable, B=np.kron(np.ones((A.shape[0]/blocksize(A), 1)), np.eye(blocksize(A))) symmetry : string 'symmetric' refers to both real and complex symmetric 'hermitian' refers to both complex Hermitian and real Hermitian 'nonsymmetric' i.e. nonsymmetric in a hermitian sense Note that for the strictly real case, symmetric and hermitian are the same Note that this flag does not denote definiteness of the operator. strength : {list} : default ['symmetric', 'classical', 'evolution', 'algebraic_distance', 'affinity', ('predefined', {'C' : csr_matrix}), None] Method used to determine the strength of connection between unknowns of the linear system. Method-specific parameters may be passed in using a tuple, e.g. strength=('symmetric',{'theta' : 0.25 }). If strength=None, all nonzero entries of the matrix are considered strong. See notes below for varying this parameter on a per level basis. Also, see notes below for using a predefined strength matrix on each level. aggregate : {list} : default ['standard', 'lloyd', 'naive', ('predefined', {'AggOp' : csr_matrix})] Method used to aggregate nodes. See notes below for varying this parameter on a per level basis. Also, see notes below for using a predefined aggregation on each level. smooth : {list} : default ['energy', None] Method used to smooth the tentative prolongator. Method-specific parameters may be passed in using a tuple, e.g. smooth= ('energy',{'krylov' : 'gmres'}). Only 'energy' and None are valid prolongation smoothing options. See notes below for varying this parameter on a per level basis. presmoother : {tuple, string, list} : default ('block_gauss_seidel', {'sweep':'symmetric'}) Defines the presmoother for the multilevel cycling. The default block Gauss-Seidel option defaults to point-wise Gauss-Seidel, if the matrix is CSR or is a BSR matrix with blocksize of 1. See notes below for varying this parameter on a per level basis. postsmoother : {tuple, string, list} Same as presmoother, except defines the postsmoother. improve_candidates : {tuple, string, list} : default [('block_gauss_seidel', {'sweep': 'symmetric', 'iterations': 4}), None] The ith entry defines the method used to improve the candidates B on level i. If the list is shorter than max_levels, then the last entry will define the method for all levels lower. If tuple or string, then this single relaxation descriptor defines improve_candidates on all levels. The list elements are relaxation descriptors of the form used for presmoother and postsmoother. A value of None implies no action on B. max_levels : {integer} : default 10 Maximum number of levels to be used in the multilevel solver. max_coarse : {integer} : default 500 Maximum number of variables permitted on the coarse grid. diagonal_dominance : {bool, tuple} : default False If True (or the first tuple entry is True), then avoid coarsening diagonally dominant rows. The second tuple entry requires a dictionary, where the key value 'theta' is used to tune the diagonal dominance threshold. keep : {bool} : default False Flag to indicate keeping extra operators in the hierarchy for diagnostics. For example, if True, then strength of connection (C), tentative prolongation (T), aggregation (AggOp), and arrays storing the C-points (Cpts) and F-points (Fpts) are kept at each level. Other Parameters ---------------- cycle_type : ['V','W','F'] Structrure of multigrid cycle coarse_solver : ['splu', 'lu', 'cholesky, 'pinv', 'gauss_seidel', ... ] Solver used at the coarsest level of the MG hierarchy. Optionally, may be a tuple (fn, args), where fn is a string such as ['splu', 'lu', ...] or a callable function, and args is a dictionary of arguments to be passed to fn. Returns ------- ml : multilevel_solver Multigrid hierarchy of matrices and prolongation operators See Also -------- multilevel_solver, aggregation.smoothed_aggregation_solver, classical.ruge_stuben_solver Notes ----- - Root-node style SA differs from classical SA primarily by preserving and identity block in the interpolation operator, P. Each aggregate has a "root-node" or "center-node" associated with it, and this root-node is injected from the coarse grid to the fine grid. The injection corresponds to the identity block. - Only smooth={'energy', None} is supported for prolongation smoothing. See reference [2011OlScTu]_ below for more details on why the 'energy' prolongation smoother is the natural counterpart to root-node style SA. - The additional parameters are passed through as arguments to multilevel_solver. Refer to pyamg.multilevel_solver for additional documentation. - At each level, four steps are executed in order to define the coarser level operator. 1. Matrix A is given and used to derive a strength matrix, C. 2. Based on the strength matrix, indices are grouped or aggregated. 3. The aggregates define coarse nodes and a tentative prolongation operator T is defined by injection 4. The tentative prolongation operator is smoothed by a relaxation scheme to improve the quality and extent of interpolation from the aggregates to fine nodes. - The parameters smooth, strength, aggregate, presmoother, postsmoother can be varied on a per level basis. For different methods on different levels, use a list as input so that the i-th entry defines the method at the i-th level. If there are more levels in the hierarchy than list entries, the last entry will define the method for all levels lower. Examples are: smooth=[('jacobi', {'omega':1.0}), None, 'jacobi'] presmoother=[('block_gauss_seidel', {'sweep':symmetric}), 'sor'] aggregate=['standard', 'naive'] strength=[('symmetric', {'theta':0.25}), ('symmetric', {'theta':0.08})] - Predefined strength of connection and aggregation schemes can be specified. These options are best used together, but aggregation can be predefined while strength of connection is not. For predefined strength of connection, use a list consisting of tuples of the form ('predefined', {'C' : C0}), where C0 is a csr_matrix and each degree-of-freedom in C0 represents a supernode. For instance to predefine a three-level hierarchy, use [('predefined', {'C' : C0}), ('predefined', {'C' : C1}) ]. Similarly for predefined aggregation, use a list of tuples. For instance to predefine a three-level hierarchy, use [('predefined', {'AggOp' : Agg0}), ('predefined', {'AggOp' : Agg1}) ], where the dimensions of A, Agg0 and Agg1 are compatible, i.e. Agg0.shape[1] == A.shape[0] and Agg1.shape[1] == Agg0.shape[0]. Each AggOp is a csr_matrix. Because this is a root-nodes solver, if a member of the predefined aggregation list is predefined, it must be of the form ('predefined', {'AggOp' : Agg, 'Cnodes' : Cnodes}). Examples -------- >>> from pyamg import rootnode_solver >>> from pyamg.gallery import poisson >>> from scipy.sparse.linalg import cg >>> import numpy as np >>> A = poisson((100, 100), format='csr') # matrix >>> b = np.ones((A.shape[0])) # RHS >>> ml = rootnode_solver(A) # AMG solver >>> M = ml.aspreconditioner(cycle='V') # preconditioner >>> x, info = cg(A, b, tol=1e-8, maxiter=30, M=M) # solve with CG References ---------- .. [1996VaMa] Vanek, P. and Mandel, J. and Brezina, M., "Algebraic Multigrid by Smoothed Aggregation for Second and Fourth Order Elliptic Problems", Computing, vol. 56, no. 3, pp. 179--196, 1996. http://citeseer.ist.psu.edu/vanek96algebraic.html .. [2011OlScTu] Olson, L. and Schroder, J. and Tuminaro, R., "A general interpolation strategy for algebraic multigrid using energy minimization", SIAM Journal on Scientific Computing (SISC), vol. 33, pp. 966--991, 2011. """ if not (isspmatrix_csr(A) or isspmatrix_bsr(A)): try: A = csr_matrix(A) warn("Implicit conversion of A to CSR", SparseEfficiencyWarning) except: raise TypeError('Argument A must have type csr_matrix, \ bsr_matrix, or be convertible to csr_matrix') A = A.asfptype() if (symmetry != 'symmetric') and (symmetry != 'hermitian') and \ (symmetry != 'nonsymmetric'): raise ValueError('expected \'symmetric\', \'nonsymmetric\' \ or \'hermitian\' for the symmetry parameter ') A.symmetry = symmetry if A.shape[0] != A.shape[1]: raise ValueError('expected square matrix') # Right near nullspace candidates use constant for each variable as default if B is None: B = np.kron( np.ones((int(A.shape[0] / blocksize(A)), 1), dtype=A.dtype), np.eye(blocksize(A))) else: B = np.asarray(B, dtype=A.dtype) if len(B.shape) == 1: B = B.reshape(-1, 1) if B.shape[0] != A.shape[0]: raise ValueError('The near null-space modes B have incorrect \ dimensions for matrix A') if B.shape[1] < blocksize(A): raise ValueError('B.shape[1] must be >= the blocksize of A') # Left near nullspace candidates if A.symmetry == 'nonsymmetric': if BH is None: BH = B.copy() else: BH = np.asarray(BH, dtype=A.dtype) if len(BH.shape) == 1: BH = BH.reshape(-1, 1) if BH.shape[1] != B.shape[1]: raise ValueError('The number of left and right near \ null-space modes B and BH, must be equal') if BH.shape[0] != A.shape[0]: raise ValueError('The near null-space modes BH have \ incorrect dimensions for matrix A') # Levelize the user parameters, so that they become lists describing the # desired user option on each level. max_levels, max_coarse, strength =\ levelize_strength_or_aggregation(strength, max_levels, max_coarse) max_levels, max_coarse, aggregate =\ levelize_strength_or_aggregation(aggregate, max_levels, max_coarse) improve_candidates =\ levelize_smooth_or_improve_candidates(improve_candidates, max_levels) smooth = levelize_smooth_or_improve_candidates(smooth, max_levels) # Construct multilevel structure levels = [] levels.append(multilevel_solver.level()) levels[-1].A = A # matrix # Append near nullspace candidates levels[-1].B = B # right candidates if A.symmetry == 'nonsymmetric': levels[-1].BH = BH # left candidates while len(levels) < max_levels and \ int(levels[-1].A.shape[0]/blocksize(levels[-1].A)) > max_coarse: extend_hierarchy(levels, strength, aggregate, smooth, improve_candidates, diagonal_dominance, keep) ml = multilevel_solver(levels, **kwargs) change_smoothers(ml, presmoother, postsmoother) return ml
def make_system(A, x, b, formats=None): """ Return A,x,b suitable for relaxation or raise an exception Parameters ---------- A : {sparse-matrix} n x n system x : {array} n-vector, initial guess b : {array} n-vector, right-hand side formats: {'csr', 'csc', 'bsr', 'lil', 'dok',...} desired sparse matrix format default is no change to A's format Returns ------- (A,x,b), where A is in the desired sparse-matrix format and x and b are "raveled", i.e. (n,) vectors. Notes ----- Does some rudimentary error checking on the system, such as checking for compatible dimensions and checking for compatible type, i.e. float or complex. Examples -------- >>> from pyamg.relaxation.relaxation import make_system >>> from pyamg.gallery import poisson >>> import numpy as np >>> A = poisson((10,10), format='csr') >>> x = np.zeros((A.shape[0],1)) >>> b = np.ones((A.shape[0],1)) >>> (A,x,b) = make_system(A,x,b,formats=['csc']) >>> print str(x.shape) (100,) >>> print str(b.shape) (100,) >>> print A.format csc """ if formats is None: pass elif formats == ['csr']: if sparse.isspmatrix_csr(A): pass elif sparse.isspmatrix_bsr(A): A = A.tocsr() else: warn('implicit conversion to CSR', sparse.SparseEfficiencyWarning) A = sparse.csr_matrix(A) else: if sparse.isspmatrix(A) and A.format in formats: pass else: A = sparse.csr_matrix(A).asformat(formats[0]) if not isinstance(x, np.ndarray): raise ValueError('expected numpy array for argument x') if not isinstance(b, np.ndarray): raise ValueError('expected numpy array for argument b') M, N = A.shape if M != N: raise ValueError('expected square matrix') if x.shape not in [(M, ), (M, 1)]: raise ValueError('x has invalid dimensions') if b.shape not in [(M, ), (M, 1)]: raise ValueError('b has invalid dimensions') if A.dtype != x.dtype or A.dtype != b.dtype: raise TypeError('arguments A, x, and b must have the same dtype') if not x.flags.carray: raise ValueError('x must be contiguous in memory') x = np.ravel(x) b = np.ravel(b) return A, x, b
def energy_prolongation_smoother(A, T, Atilde, B, Bf, Cpt_params, krylov='cg', maxiter=4, tol=1e-8, degree=1, weighting='local'): """Minimize the energy of the coarse basis functions (columns of T). Both root-node and non-root-node style prolongation smoothing is available, see Cpt_params description below. Parameters ---------- A : {csr_matrix, bsr_matrix} Sparse NxN matrix T : {bsr_matrix} Tentative prolongator, a NxM sparse matrix (M < N) Atilde : {csr_matrix} Strength of connection matrix B : {array} Near-nullspace modes for coarse grid. Has shape (M,k) where k is the number of coarse candidate vectors. Bf : {array} Near-nullspace modes for fine grid. Has shape (N,k) where k is the number of coarse candidate vectors. Cpt_params : {tuple} Tuple of the form (bool, dict). If the Cpt_params[0] = False, then the standard SA prolongation smoothing is carried out. If True, then root-node style prolongation smoothing is carried out. The dict must be a dictionary of parameters containing, (1) P_I: P_I.T is the injection matrix for the Cpts, (2) I_F: an identity matrix for only the F-points (i.e. I, but with zero rows and columns for C-points) and I_C: the C-point analogue to I_F. See Notes below for more information. krylov : {string} 'cg' : for SPD systems. Solve A T = 0 in a constraint space with CG 'cgnr' : for nonsymmetric and/or indefinite systems. Solve A T = 0 in a constraint space with CGNR 'gmres' : for nonsymmetric and/or indefinite systems. Solve A T = 0 in a constraint space with GMRES maxiter : integer Number of energy minimization steps to apply to the prolongator tol : {scalar} Minimization tolerance degree : {int} Generate sparsity pattern for P based on (Atilde^degree T) weighting : {string} 'block', 'diagonal' or 'local' construction of the diagonal preconditioning 'local': Uses a local row-wise weight based on the Gershgorin estimate. Avoids any potential under-damping due to inaccurate spectral radius estimates. 'block': If A is a BSR matrix, use a block diagonal inverse of A 'diagonal': Use inverse of the diagonal of A Returns ------- T : {bsr_matrix} Smoothed prolongator Notes ----- Only 'diagonal' weighting is supported for the CGNR method, because we are working with A^* A and not A. When Cpt_params[0] == True, root-node style prolongation smoothing is used to minimize the energy of columns of T. Essentially, an identity block is maintained in T, corresponding to injection from the coarse-grid to the fine-grid root-nodes. See [2] for more details, and see util.utils.get_Cpt_params for the helper function to generate Cpt_params. If Cpt_params[0] == False, the energy of columns of T are still minimized, but without maintaining the identity block. Examples -------- >>> from pyamg.aggregation import energy_prolongation_smoother >>> from pyamg.gallery import poisson >>> from scipy.sparse import coo_matrix >>> import numpy as np >>> data = np.ones((6,)) >>> row = np.arange(0,6) >>> col = np.kron([0,1],np.ones((3,))) >>> T = coo_matrix((data,(row,col)),shape=(6,2)).tocsr() >>> print T.todense() [[ 1. 0.] [ 1. 0.] [ 1. 0.] [ 0. 1.] [ 0. 1.] [ 0. 1.]] >>> A = poisson((6,),format='csr') >>> B = np.ones((2,1),dtype=float) >>> P = energy_prolongation_smoother(A,T,A,B, None, (False,{})) >>> print P.todense() [[ 1. 0. ] [ 1. 0. ] [ 0.66666667 0.33333333] [ 0.33333333 0.66666667] [ 0. 1. ] [ 0. 1. ]] References ---------- .. [1] Jan Mandel, Marian Brezina, and Petr Vanek "Energy Optimization of Algebraic Multigrid Bases" Computing 62, 205-228, 1999 http://dx.doi.org/10.1007/s006070050022 .. [2] Olson, L. and Schroder, J. and Tuminaro, R., "A general interpolation strategy for algebraic multigrid using energy minimization", SIAM Journal on Scientific Computing (SISC), vol. 33, pp. 966--991, 2011. """ # ==================================================================== # Test Inputs if maxiter < 0: raise ValueError('maxiter must be > 0') if tol > 1: raise ValueError('tol must be <= 1') if sparse.isspmatrix_csr(A): A = A.tobsr(blocksize=(1, 1), copy=False) elif sparse.isspmatrix_bsr(A): pass else: raise TypeError("A must be csr_matrix or bsr_matrix") if sparse.isspmatrix_csr(T): T = T.tobsr(blocksize=(1, 1), copy=False) elif sparse.isspmatrix_bsr(T): pass else: raise TypeError("T must be csr_matrix or bsr_matrix") if Atilde is None: AtildeCopy = sparse.csr_matrix( (np.ones(len(A.indices)), A.indices.copy(), A.indptr.copy()), shape=(A.shape[0] / A.blocksize[0], A.shape[1] / A.blocksize[1])) else: AtildeCopy = Atilde.copy() if not sparse.isspmatrix_csr(AtildeCopy): raise TypeError("Atilde must be csr_matrix") if T.blocksize[0] != A.blocksize[0]: raise ValueError("T row-blocksize should be the same as A blocksize") if B.shape[0] != T.shape[1]: raise ValueError("B is the candidates for the coarse grid. \ num_rows(b) = num_cols(T)") if min(T.nnz, AtildeCopy.nnz, A.nnz) == 0: return T # Expand allowed sparsity pattern for P through multiplication by Atilde T.sort_indices() Sparsity_Pattern = sparse.csr_matrix( (np.ones(T.indices.shape), T.indices, T.indptr), shape=(T.shape[0] / T.blocksize[0], T.shape[1] / T.blocksize[1])) AtildeCopy.data[:] = 1.0 for i in range(degree): Sparsity_Pattern = AtildeCopy * Sparsity_Pattern # UnAmal returns a BSR matrix Sparsity_Pattern = UnAmal(Sparsity_Pattern, T.blocksize[0], T.blocksize[1]) Sparsity_Pattern.sort_indices() # If using root nodes, enforce identity at C-points if Cpt_params[0]: Sparsity_Pattern = Cpt_params[1]['I_F'] * Sparsity_Pattern Sparsity_Pattern = Cpt_params[1]['P_I'] + Sparsity_Pattern # Construct array of inv(Bi'Bi), where Bi is B restricted to row i's # sparsity pattern in Sparsity Pattern. This array is used multiple times # in Satisfy_Constraints(...). BtBinv = compute_BtBinv(B, Sparsity_Pattern) # If using root nodes and B has more columns that A's blocksize, then # T must be updated so that T*B = Bfine if Cpt_params[0] and (B.shape[1] > A.blocksize[0]): T = filter_operator(T, Sparsity_Pattern, B, Bf, BtBinv) # Ensure identity at C-pts if Cpt_params[0]: T = Cpt_params[1]['I_F'] * T + Cpt_params[1]['P_I'] # Iteratively minimize the energy of T subject to the constraints of # Sparsity_Pattern and maintaining T's effect on B, i.e. T*B = # (T+Update)*B, i.e. Update*B = 0 if krylov == 'cg': T = cg_prolongation_smoothing(A, T, B, BtBinv, Sparsity_Pattern, maxiter, tol, weighting, Cpt_params) elif krylov == 'cgnr': T = cgnr_prolongation_smoothing(A, T, B, BtBinv, Sparsity_Pattern, maxiter, tol, weighting, Cpt_params) elif krylov == 'gmres': T = gmres_prolongation_smoothing(A, T, B, BtBinv, Sparsity_Pattern, maxiter, tol, weighting, Cpt_params) T.eliminate_zeros() return T
def jacobi_prolongation_smoother(S, T, C, B, omega=4.0 / 3.0, degree=1, filter=False, weighting='diagonal'): """Jacobi prolongation smoother Parameters ---------- S : {csr_matrix, bsr_matrix} Sparse NxN matrix used for smoothing. Typically, A. T : {csr_matrix, bsr_matrix} Tentative prolongator C : {csr_matrix, bsr_matrix} Strength-of-connection matrix B : {array} Near nullspace modes for the coarse grid such that T*B exactly reproduces the fine grid near nullspace modes omega : {scalar} Damping parameter filter : {boolean} If true, filter S before smoothing T. This option can greatly control complexity. weighting : {string} 'block', 'diagonal' or 'local' weighting for constructing the Jacobi D 'local': Uses a local row-wise weight based on the Gershgorin estimate. Avoids any potential under-damping due to inaccurate spectral radius estimates. 'block': If A is a BSR matrix, use a block diagonal inverse of A 'diagonal': Classic Jacobi D = diagonal(A) Returns ------- P : {csr_matrix, bsr_matrix} Smoothed (final) prolongator defined by P = (I - omega/rho(K) K) * T where K = diag(S)^-1 * S and rho(K) is an approximation to the spectral radius of K. Notes ----- If weighting is not 'local', then results using Jacobi prolongation smoother are not precisely reproducible due to a random initial guess used for the spectral radius approximation. For precise reproducibility, set numpy.random.seed(..) to the same value before each test. Examples -------- >>> from pyamg.aggregation import jacobi_prolongation_smoother >>> from pyamg.gallery import poisson >>> from scipy.sparse import coo_matrix >>> import numpy as np >>> data = np.ones((6,)) >>> row = np.arange(0,6) >>> col = np.kron([0,1],np.ones((3,))) >>> T = coo_matrix((data,(row,col)),shape=(6,2)).tocsr() >>> T.todense() matrix([[ 1., 0.], [ 1., 0.], [ 1., 0.], [ 0., 1.], [ 0., 1.], [ 0., 1.]]) >>> A = poisson((6,),format='csr') >>> P = jacobi_prolongation_smoother(A,T,A,np.ones((2,1))) >>> P.todense() matrix([[ 0.64930164, 0. ], [ 1. , 0. ], [ 0.64930164, 0.35069836], [ 0.35069836, 0.64930164], [ 0. , 1. ], [ 0. , 0.64930164]]) """ # preprocess weighting if weighting == 'block': if sparse.isspmatrix_csr(S): weighting = 'diagonal' elif sparse.isspmatrix_bsr(S): if S.blocksize[0] == 1: weighting = 'diagonal' if filter: # Implement filtered prolongation smoothing for the general case by # utilizing satisfy constraints if sparse.isspmatrix_bsr(S): numPDEs = S.blocksize[0] else: numPDEs = 1 # Create a filtered S with entries dropped that aren't in C C = UnAmal(C, numPDEs, numPDEs) S = S.multiply(C) S.eliminate_zeros() if weighting == 'diagonal': # Use diagonal of S D_inv = get_diagonal(S, inv=True) D_inv_S = scale_rows(S, D_inv, copy=True) D_inv_S = (omega / approximate_spectral_radius(D_inv_S)) * D_inv_S elif weighting == 'block': # Use block diagonal of S D_inv = get_block_diag(S, blocksize=S.blocksize[0], inv_flag=True) D_inv = sparse.bsr_matrix( (D_inv, np.arange(D_inv.shape[0]), np.arange(D_inv.shape[0] + 1)), shape=S.shape) D_inv_S = D_inv * S D_inv_S = (omega / approximate_spectral_radius(D_inv_S)) * D_inv_S elif weighting == 'local': # Use the Gershgorin estimate as each row's weight, instead of a global # spectral radius estimate D = np.abs(S) * np.ones((S.shape[0], 1), dtype=S.dtype) D_inv = np.zeros_like(D) D_inv[D != 0] = 1.0 / np.abs(D[D != 0]) D_inv_S = scale_rows(S, D_inv, copy=True) D_inv_S = omega * D_inv_S else: raise ValueError('Incorrect weighting option') if filter: # Carry out Jacobi, but after calculating the prolongator update, U, # apply satisfy constraints so that U*B = 0 P = T for i in range(degree): U = (D_inv_S * P).tobsr(blocksize=P.blocksize) # Enforce U*B = 0 (1) Construct array of inv(Bi'Bi), where Bi is B # restricted to row i's sparsity pattern in Sparsity Pattern. This # array is used multiple times in Satisfy_Constraints(...). BtBinv = compute_BtBinv(B, U) # (2) Apply satisfy constraints Satisfy_Constraints(U, B, BtBinv) # Update P P = P - U else: # Carry out Jacobi as normal P = T for i in range(degree): P = P - (D_inv_S * P) return P
def csr_matvec(A,v,a=None,out=None,overwrite_out=True): """Calculates matrix vector products :math:`x += a A y` or :math:`x = a A y` with csr matrix. Notes ----- For QuSpin builds which support OpenMP this function will be multithreaded. Note that using out=v will result in incorrect results. Also note that if format of A is not 'csr' the matrix will be converted. Examples -------- Parameters ----------- A : scipy.spmatrix Sparse matrix to take the dot product. v : array_like array which contains the vector to take the product with. a : scalar, optional value to scale the vector with after the product with `A` is taken. out : array_like output array to put the results of the calculation. overwrite_out : bool, optional If set to `True`, the function overwrites the values in `out` with the result. otherwise the result is added to the values in `out`. Returns -------- numpy.ndarray result of :math:`\\a A v`. If `out` is not None and `overwrite_out = True` the dunction returns `out` with the data overwritten, otherwise if `overwrite_out = False` the result is added to `out`. If `out` is None the result is stored in a new array which is returned by the function. """ if not issparse(A): raise ValueError("Expecting sparse matrix for 'A'.") if not isspmatrix_csr(A): A = A.tocsr() if a is None: a = 1.0 result_type=_np.result_type(v.dtype,A.dtype,a) if A.shape[1]!=v.size: raise ValueError("dimension mismatch with shapes {} and {}".format(A.shape,v.shape)) if out is None: out = _np.zeros_like(v,dtype=result_type) overwrite_out = True else: out = _np.asarray(out) if v.dtype != result_type: v = v.astype(result_type) if out.shape != v.shape: raise ValueError("ValueError: output array is not the correct shape or dtype.") _csr_matvec(overwrite_out,A.indptr,A.indices,A.data,a,v.ravel(),out.ravel()) return out
def transform(self, X): """Transform data to polynomial features. Parameters ---------- X : {array-like, sparse matrix} of shape (n_samples, n_features) The data to transform, row by row. Prefer CSR over CSC for sparse input (for speed), but CSC is required if the degree is 4 or higher. If the degree is less than 4 and the input format is CSC, it will be converted to CSR, have its polynomial features generated, then converted back to CSC. If the degree is 2 or 3, the method described in "Leveraging Sparsity to Speed Up Polynomial Feature Expansions of CSR Matrices Using K-Simplex Numbers" by Andrew Nystrom and John Hughes is used, which is much faster than the method used on CSC input. For this reason, a CSC input will be converted to CSR, and the output will be converted back to CSC prior to being returned, hence the preference of CSR. Returns ------- XP : {ndarray, sparse matrix} of shape (n_samples, NP) The matrix of features, where NP is the number of polynomial features generated from the combination of inputs. If a sparse matrix is provided, it will be converted into a sparse ``csr_matrix``. """ check_is_fitted(self) X = self._validate_data(X, order="F", dtype=FLOAT_DTYPES, reset=False, accept_sparse=("csr", "csc")) n_samples, n_features = X.shape if sparse.isspmatrix_csr(X): if self._max_degree > 3: return self.transform(X.tocsc()).tocsr() to_stack = [] if self.include_bias: to_stack.append( sparse.csc_matrix( np.ones(shape=(n_samples, 1), dtype=X.dtype))) if self._min_degree <= 1: to_stack.append(X) for deg in range(max(2, self._min_degree), self._max_degree + 1): Xp_next = _csr_polynomial_expansion(X.data, X.indices, X.indptr, X.shape[1], self.interaction_only, deg) if Xp_next is None: break to_stack.append(Xp_next) if len(to_stack) == 0: # edge case: deal with empty matrix XP = sparse.csr_matrix((n_samples, 0), dtype=X.dtype) else: XP = sparse.hstack(to_stack, format="csr") elif sparse.isspmatrix_csc(X) and self._max_degree < 4: return self.transform(X.tocsr()).tocsc() elif sparse.isspmatrix(X): combinations = self._combinations( n_features=n_features, min_degree=self._min_degree, max_degree=self._max_degree, interaction_only=self.interaction_only, include_bias=self.include_bias, ) columns = [] for combi in combinations: if combi: out_col = 1 for col_idx in combi: out_col = X[:, col_idx].multiply(out_col) columns.append(out_col) else: bias = sparse.csc_matrix(np.ones((X.shape[0], 1))) columns.append(bias) XP = sparse.hstack(columns, dtype=X.dtype).tocsc() else: # Do as if _min_degree = 0 and cut down array after the # computation, i.e. use _n_out_full instead of n_output_features_. XP = np.empty(shape=(n_samples, self._n_out_full), dtype=X.dtype, order=self.order) # What follows is a faster implementation of: # for i, comb in enumerate(combinations): # XP[:, i] = X[:, comb].prod(1) # This implementation uses two optimisations. # First one is broadcasting, # multiply ([X1, ..., Xn], X1) -> [X1 X1, ..., Xn X1] # multiply ([X2, ..., Xn], X2) -> [X2 X2, ..., Xn X2] # ... # multiply ([X[:, start:end], X[:, start]) -> ... # Second optimisation happens for degrees >= 3. # Xi^3 is computed reusing previous computation: # Xi^3 = Xi^2 * Xi. # degree 0 term if self.include_bias: XP[:, 0] = 1 current_col = 1 else: current_col = 0 # degree 1 term XP[:, current_col:current_col + n_features] = X index = list(range(current_col, current_col + n_features)) current_col += n_features index.append(current_col) # loop over degree >= 2 terms for _ in range(2, self._max_degree + 1): new_index = [] end = index[-1] for feature_idx in range(n_features): start = index[feature_idx] new_index.append(current_col) if self.interaction_only: start += index[feature_idx + 1] - index[feature_idx] next_col = current_col + end - start if next_col <= current_col: break # XP[:, start:end] are terms of degree d - 1 # that exclude feature #feature_idx. np.multiply( XP[:, start:end], X[:, feature_idx:feature_idx + 1], out=XP[:, current_col:next_col], casting="no", ) current_col = next_col new_index.append(current_col) index = new_index if self._min_degree > 1: n_XP, n_Xout = self._n_out_full, self.n_output_features_ if self.include_bias: Xout = np.empty(shape=(n_samples, n_Xout), dtype=XP.dtype, order=self.order) Xout[:, 0] = 1 Xout[:, 1:] = XP[:, n_XP - n_Xout + 1:] else: Xout = XP[:, n_XP - n_Xout:].copy() XP = Xout return XP
def scale(X, axis=0, with_mean=True, with_std=True, copy=True): """Standardize a dataset along any axis Center to the mean and component wise scale to unit variance. Parameters ---------- X : array-like or CSR matrix. The data to center and scale. axis : int (0 by default) axis used to compute the means and standard deviations along. If 0, independently standardize each feature, otherwise (if 1) standardize each sample. with_mean : boolean, True by default If True, center the data before scaling. with_std : boolean, True by default If True, scale the data to unit variance (or equivalently, unit standard deviation). copy : boolean, optional, default is True set to False to perform inplace row normalization and avoid a copy (if the input is already a numpy array or a scipy.sparse CSR matrix and if axis is 1). Notes ----- This implementation will refuse to center scipy.sparse matrices since it would make them non-sparse and would potentially crash the program with memory exhaustion problems. Instead the caller is expected to either set explicitly `with_mean=False` (in that case, only variance scaling will be performed on the features of the CSR matrix) or to call `X.toarray()` if he/she expects the materialized dense array to fit in memory. To avoid memory copy the caller should pass a CSR matrix. See also -------- :class:`sklearn.preprocessing.StandardScaler` to perform centering and scaling using the ``Transformer`` API (e.g. as part of a preprocessing :class:`sklearn.pipeline.Pipeline`) """ if sparse.issparse(X): if with_mean: raise ValueError( "Cannot center sparse matrices: pass `with_mean=False` instead" " See docstring for motivation and alternatives.") if axis != 0: raise ValueError("Can only scale sparse matrix on axis=0, " " got axis=%d" % axis) warn_if_not_float(X, estimator='The scale function') if not sparse.isspmatrix_csr(X): X = X.tocsr() copy = False if copy: X = X.copy() _, var = mean_variance_axis0(X) var[var == 0.0] = 1.0 inplace_column_scale(X, 1 / np.sqrt(var)) else: X = np.asarray(X) warn_if_not_float(X, estimator='The scale function') mean_, std_ = _mean_and_std(X, axis, with_mean=with_mean, with_std=with_std) if copy: X = X.copy() # Xr is a view on the original array that enables easy use of # broadcasting on the axis in which we are interested in Xr = np.rollaxis(X, axis) if with_mean: Xr -= mean_ if with_std: Xr /= std_ return X
def evolution_strength_of_connection(A, B=None, epsilon=4.0, k=2, proj_type='l2', block_flag=False, symmetrize_measure=True): """Evolution Strength Measure. Construct strength of connection matrix using an Evolution-based measure Parameters ---------- A : csr_matrix, bsr_matrix Sparse NxN matrix B : string, array If B=None, then the near nullspace vector used is all ones. If B is an (NxK) array, then B is taken to be the near nullspace vectors. epsilon : scalar Drop tolerance k : integer ODE num time steps, step size is assumed to be 1/rho(DinvA) proj_type : {'l2','D_A'} Define norm for constrained min prob, i.e. define projection block_flag : boolean If True, use a block D inverse as preconditioner for A during weighted-Jacobi Returns ------- Atilde : csr_matrix Sparse matrix of strength values See [2008OlScTu]_ for more details. References ---------- .. [2008OlScTu] Olson, L. N., Schroder, J., Tuminaro, R. S., "A New Perspective on Strength Measures in Algebraic Multigrid", submitted, June, 2008. Examples -------- >>> import numpy as np >>> from pyamg.gallery import stencil_grid >>> from pyamg.strength import evolution_strength_of_connection >>> n=3 >>> stencil = np.array([[-1.0,-1.0,-1.0], ... [-1.0, 8.0,-1.0], ... [-1.0,-1.0,-1.0]]) >>> A = stencil_grid(stencil, (n,n), format='csr') >>> S = evolution_strength_of_connection(A, np.ones((A.shape[0],1))) """ # ==================================================================== # Check inputs if epsilon < 1.0: raise ValueError('expected epsilon > 1.0') if k <= 0: raise ValueError('number of time steps must be > 0') if proj_type not in ['l2', 'D_A']: raise ValueError('proj_type must be "l2" or "D_A"') if (not sparse.isspmatrix_csr(A)) and (not sparse.isspmatrix_bsr(A)): raise TypeError('expected csr_matrix or bsr_matrix') # ==================================================================== # Format A and B correctly. # B must be in mat format, this isn't a deep copy if B is None: Bmat = np.ones((A.shape[0], 1), dtype=A.dtype) else: Bmat = np.asarray(B) # Pre-process A. We need A in CSR, to be devoid of explicit 0's and have # sorted indices if not sparse.isspmatrix_csr(A): csrflag = False numPDEs = A.blocksize[0] D = A.diagonal() # Calculate Dinv*A if block_flag: Dinv = get_block_diag(A, blocksize=numPDEs, inv_flag=True) Dinv = sparse.bsr_matrix( (Dinv, np.arange(Dinv.shape[0]), np.arange(Dinv.shape[0] + 1)), shape=A.shape) Dinv_A = (Dinv * A).tocsr() else: Dinv = np.zeros_like(D) mask = (D != 0.0) Dinv[mask] = 1.0 / D[mask] Dinv[D == 0] = 1.0 Dinv_A = scale_rows(A, Dinv, copy=True) A = A.tocsr() else: csrflag = True numPDEs = 1 D = A.diagonal() Dinv = np.zeros_like(D) mask = (D != 0.0) Dinv[mask] = 1.0 / D[mask] Dinv[D == 0] = 1.0 Dinv_A = scale_rows(A, Dinv, copy=True) A.eliminate_zeros() A.sort_indices() # Handle preliminaries for the algorithm dimen = A.shape[1] NullDim = Bmat.shape[1] # Get spectral radius of Dinv*A, this will be used to scale the time step # size for the ODE rho_DinvA = approximate_spectral_radius(Dinv_A) # Calculate D_A for later use in the minimization problem if proj_type == 'D_A': D_A = sparse.spdiags([D], [0], dimen, dimen, format='csr') else: D_A = sparse.eye(dimen, dimen, format='csr', dtype=A.dtype) # Calculate (I - delta_t Dinv A)^k # In order to later access columns, we calculate the transpose in # CSR format so that columns will be accessed efficiently # Calculate the number of time steps that can be done by squaring, and # the number of time steps that must be done incrementally nsquare = int(np.log2(k)) ninc = k - 2**nsquare # Calculate one time step Id = sparse.eye(dimen, dimen, format='csr', dtype=A.dtype) Atilde = (Id - (1.0 / rho_DinvA) * Dinv_A) Atilde = Atilde.T.tocsr() # Construct a sparsity mask for Atilde that will restrict Atilde^T to the # nonzero pattern of A, with the added constraint that row i of Atilde^T # retains only the nonzeros that are also in the same PDE as i. mask = A.copy() # Restrict to same PDE if numPDEs > 1: row_length = np.diff(mask.indptr) my_pde = np.mod(np.arange(dimen), numPDEs) my_pde = np.repeat(my_pde, row_length) mask.data[np.mod(mask.indices, numPDEs) != my_pde] = 0.0 del row_length, my_pde mask.eliminate_zeros() # If the total number of time steps is a power of two, then there is # a very efficient computational short-cut. Otherwise, we support # other numbers of time steps, through an inefficient algorithm. if ninc > 0: warn( 'The most efficient time stepping for the Evolution Strength ' f'Method is done in powers of two.\nYou have chosen {k} time steps.' ) # Calculate (Atilde^nsquare)^T = (Atilde^T)^nsquare for _i in range(nsquare): Atilde = Atilde * Atilde JacobiStep = (Id - (1.0 / rho_DinvA) * Dinv_A).T.tocsr() for _i in range(ninc): Atilde = Atilde * JacobiStep del JacobiStep # Apply mask to Atilde, zeros in mask have already been eliminated at # start of routine. mask.data[:] = 1.0 Atilde = Atilde.multiply(mask) Atilde.eliminate_zeros() Atilde.sort_indices() elif nsquare == 0: if numPDEs > 1: # Apply mask to Atilde, zeros in mask have already been eliminated # at start of routine. mask.data[:] = 1.0 Atilde = Atilde.multiply(mask) Atilde.eliminate_zeros() Atilde.sort_indices() else: # Use computational short-cut for case (ninc == 0) and (nsquare > 0) # Calculate Atilde^k only at the sparsity pattern of mask. for _i in range(nsquare - 1): Atilde = Atilde * Atilde # Call incomplete mat-mat mult AtildeCSC = Atilde.tocsc() AtildeCSC.sort_indices() mask.sort_indices() Atilde.sort_indices() amg_core.incomplete_mat_mult_csr(Atilde.indptr, Atilde.indices, Atilde.data, AtildeCSC.indptr, AtildeCSC.indices, AtildeCSC.data, mask.indptr, mask.indices, mask.data, dimen) del AtildeCSC, Atilde Atilde = mask Atilde.eliminate_zeros() Atilde.sort_indices() del Dinv, Dinv_A, mask # Calculate strength based on constrained min problem of # min( z - B*x ), such that # (B*x)|_i = z|_i, i.e. they are equal at point i # z = (I - (t/k) Dinv A)^k delta_i # # Strength is defined as the relative point-wise approx. error between # B*x and z. We don't use the full z in this problem, only that part of # z that is in the sparsity pattern of A. # # Can use either the D-norm, and inner product, or l2-norm and inner-prod # to solve the constrained min problem. Using D gives scale invariance. # # This is a quadratic minimization problem with a linear constraint, so # we can build a linear system and solve it to find the critical point, # i.e. minimum. # # We exploit a known shortcut for the case of NullDim = 1. The shortcut is # mathematically equivalent to the longer constrained min. problem if NullDim == 1: # Use shortcut to solve constrained min problem if B is only a vector # Strength(i,j) = | 1 - (z(i)/b(j))/(z(j)/b(i)) | # These ratios can be calculated by diagonal row and column scalings # Create necessary vectors for scaling Atilde # Its not clear what to do where B == 0. This is an # an easy programming solution, that may make sense. Bmat_forscaling = np.ravel(Bmat) Bmat_forscaling[Bmat_forscaling == 0] = 1.0 DAtilde = Atilde.diagonal() DAtildeDivB = np.ravel(DAtilde) / Bmat_forscaling # Calculate best approximation, z_tilde, in span(B) # Importantly, scale_rows and scale_columns leave zero entries # in the matrix. For previous implementations this was useful # because we assume data and Atilde.data are the same length below data = Atilde.data.copy() Atilde.data[:] = 1.0 Atilde = scale_rows(Atilde, DAtildeDivB) Atilde = scale_columns(Atilde, np.ravel(Bmat_forscaling)) # If angle in the complex plane between z and z_tilde is # greater than 90 degrees, then weak. We can just look at the # dot product to determine if angle is greater than 90 degrees. angle = np.multiply(np.real(Atilde.data), np.real(data)) +\ np.multiply(np.imag(Atilde.data), np.imag(data)) angle = angle < 0.0 angle = np.array(angle, dtype=bool) # Calculate Approximation ratio Atilde.data = Atilde.data / data # If approximation ratio is less than tol, then weak connection weak_ratio = (np.abs(Atilde.data) < 1e-4) # Calculate Approximation error Atilde.data = abs(1.0 - Atilde.data) # Set small ratios and large angles to weak Atilde.data[weak_ratio] = 0.0 Atilde.data[angle] = 0.0 # Set near perfect connections to 1e-4 Atilde.eliminate_zeros() Atilde.data[Atilde.data < np.sqrt(np.finfo(float).eps)] = 1e-4 del data, weak_ratio, angle else: # For use in computing local B_i^H*B, precompute the element-wise # multiply of each column of B with each other column. We also scale # by 2.0 to account for BDB's eventual use in a constrained # minimization problem BDBCols = int(np.sum(np.arange(NullDim + 1))) BDB = np.zeros((dimen, BDBCols), dtype=A.dtype) counter = 0 for i in range(NullDim): for j in range(i, NullDim): BDB[:, counter] = 2.0 *\ (np.conjugate(np.ravel(Bmat[:, i])) * np.ravel(D_A * Bmat[:, j])) counter = counter + 1 # Choose tolerance for dropping "numerically zero" values later tol = set_tol(Atilde.dtype) # Use constrained min problem to define strength amg_core.evolution_strength_helper(Atilde.data, Atilde.indptr, Atilde.indices, Atilde.shape[0], np.ravel(Bmat), np.ravel((D_A * B.conj()).T), np.ravel(BDB), BDBCols, NullDim, tol) Atilde.eliminate_zeros() # All of the strength values are real by this point, so ditch the complex # part Atilde.data = np.array(np.real(Atilde.data), dtype=float) # Apply drop tolerance if epsilon != np.inf: amg_core.apply_distance_filter(dimen, epsilon, Atilde.indptr, Atilde.indices, Atilde.data) Atilde.eliminate_zeros() # Symmetrize if symmetrize_measure: Atilde = 0.5 * (Atilde + Atilde.T) # Set diagonal to 1.0, as each point is strongly connected to itself. Id = sparse.eye(dimen, dimen, format='csr') Id.data -= Atilde.diagonal() Atilde = Atilde + Id # If converted BSR to CSR, convert back and return amalgamated matrix, # i.e. the sparsity structure of the blocks of Atilde if not csrflag: Atilde = Atilde.tobsr(blocksize=(numPDEs, numPDEs)) n_blocks = Atilde.indices.shape[0] blocksize = Atilde.blocksize[0] * Atilde.blocksize[1] CSRdata = np.zeros((n_blocks, )) amg_core.min_blocks(n_blocks, blocksize, np.ravel(np.asarray(Atilde.data)), CSRdata) # Atilde = sparse.csr_matrix((data, row, col), shape=(*,*)) Atilde = sparse.csr_matrix((CSRdata, Atilde.indices, Atilde.indptr), shape=(int(Atilde.shape[0] / numPDEs), int(Atilde.shape[1] / numPDEs))) # Standardized strength values require small values be weak and large # values be strong. So, we invert the algebraic distances computed here Atilde.data = 1.0 / Atilde.data # Scale C by the largest magnitude entry in each row Atilde = scale_rows_by_largest_entry(Atilde) return Atilde
def test_jmat_type(): "Operator CSR Type: spin ops" for k in ['x', 'y', 'z', '+', '-']: op = jmat(1 / 2, k) assert_equal(isspmatrix_csr(op.data), True)
def symmetric_strength_of_connection(A, theta=0): """Symmetric Strength Measure. Compute strength of connection matrix using the standard symmetric measure An off-diagonal connection A[i,j] is strong iff:: abs(A[i,j]) >= theta * sqrt( abs(A[i,i]) * abs(A[j,j]) ) Parameters ---------- A : csr_matrix Matrix graph defined in sparse format. Entry A[i,j] describes the strength of edge [i,j] theta : float Threshold parameter (positive). Returns ------- S : csr_matrix Matrix graph defining strong connections. S[i,j]=1 if vertex i is strongly influenced by vertex j. See Also -------- symmetric_strength_of_connection : symmetric measure used in SA evolution_strength_of_connection : relaxation based strength measure Notes ----- - For vector problems, standard strength measures may produce undesirable aggregates. A "block approach" from Vanek et al. is used to replace vertex comparisons with block-type comparisons. A connection between nodes i and j in the block case is strong if:: ||AB[i,j]|| >= theta * sqrt( ||AB[i,i]||*||AB[j,j]|| ) where AB[k,l] is the matrix block (degrees of freedom) associated with nodes k and l and ||.|| is a matrix norm, such a Frobenius. - See [1996bVaMaBr]_ for more details. References ---------- .. [1996bVaMaBr] Vanek, P. and Mandel, J. and Brezina, M., "Algebraic Multigrid by Smoothed Aggregation for Second and Fourth Order Elliptic Problems", Computing, vol. 56, no. 3, pp. 179--196, 1996. http://citeseer.ist.psu.edu/vanek96algebraic.html Examples -------- >>> import numpy as np >>> from pyamg.gallery import stencil_grid >>> from pyamg.strength import symmetric_strength_of_connection >>> n=3 >>> stencil = np.array([[-1.0,-1.0,-1.0], ... [-1.0, 8.0,-1.0], ... [-1.0,-1.0,-1.0]]) >>> A = stencil_grid(stencil, (n,n), format='csr') >>> S = symmetric_strength_of_connection(A, 0.0) """ if theta < 0: raise ValueError('expected a positive theta') if not sparse.isspmatrix_csr(A) and not sparse.isspmatrix_bsr(A): raise TypeError('expected csr_matrix or bsr_matrix') if sparse.isspmatrix_csr(A): # if theta == 0: # return A Sp = np.empty_like(A.indptr) Sj = np.empty_like(A.indices) Sx = np.empty_like(A.data) fn = amg_core.symmetric_strength_of_connection fn(A.shape[0], theta, A.indptr, A.indices, A.data, Sp, Sj, Sx) S = sparse.csr_matrix((Sx, Sj, Sp), shape=A.shape) elif sparse.isspmatrix_bsr(A): M, N = A.shape R, C = A.blocksize if R != C: raise ValueError('matrix must have square blocks') if theta == 0: data = np.ones(len(A.indices), dtype=A.dtype) S = sparse.csr_matrix((data, A.indices.copy(), A.indptr.copy()), shape=(int(M / R), int(N / C))) else: # the strength of connection matrix is based on the # Frobenius norms of the blocks data = (np.conjugate(A.data) * A.data).reshape(-1, R * C) data = data.sum(axis=1) A = sparse.csr_matrix((data, A.indices, A.indptr), shape=(int(M / R), int(N / C))) return symmetric_strength_of_connection(A, theta) # Strength represents "distance", so take the magnitude S.data = np.abs(S.data) # Scale S by the largest magnitude entry in each row S = scale_rows_by_largest_entry(S) return S
def w_clip(w1, w2, outSP=True, silence_warnings=False): ''' Clip a continuous W object (w1) with a different W object (w2) so only cells where w2 has a non-zero value remain with non-zero values in w1. Checks on w1 and w2 are performed to make sure they conform to the appropriate format and, if not, they are converted. Parameters ---------- w1 : W W, scipy.sparse.csr.csr_matrix Potentially continuous weights matrix to be clipped. The clipped matrix wc will have at most the same elements as w1. w2 : W W, scipy.sparse.csr.csr_matrix Weights matrix to use as shell to clip w1. Automatically converted to binary format. Only non-zero elements in w2 will be kept non-zero in wc. NOTE: assumed to be of the same shape as w1 outSP : boolean If True (default) return sparse version of the clipped W, if False, return W object of the clipped matrix silence_warnings : boolean Switch to turn off (default on) print statements for every observation with islands Returns ------- wc : W W, scipy.sparse.csr.csr_matrix Clipped W object (sparse if outSP=Ture). It inherits ``id_order`` from w1. Examples -------- >>> from libpysal.weights import lat2W First create a W object from a lattice using queen contiguity and row-standardize it (note that these weights will stay when we clip the object, but they will not neccesarily represent a row-standardization anymore): >>> w1 = lat2W(3, 2, rook=False) >>> w1.transform = 'R' We will clip that geography assuming observations 0, 2, 3 and 4 belong to one group and 1, 5 belong to another group and we don't want both groups to interact with each other in our weights (i.e. w_ij = 0 if i and j in different groups). For that, we use the following method: >>> import libpysal >>> w2 = libpysal.weights.block_weights(['r1', 'r2', 'r1', 'r1', 'r1', 'r2']) To illustrate that w2 will only be considered as binary even when the object passed is not, we can row-standardize it >>> w2.transform = 'R' The clipped object ``wc`` will contain only the spatial queen relationships that occur within one group ('r1' or 'r2') but will have gotten rid of those that happen across groups >>> wcs = libpysal.weights.w_clip(w1, w2, outSP=True) This will create a sparse object (recommended when n is large). >>> wcs.sparse.toarray() array([[0. , 0. , 0.33333333, 0.33333333, 0. , 0. ], [0. , 0. , 0. , 0. , 0. , 0. ], [0.2 , 0. , 0. , 0.2 , 0.2 , 0. ], [0.2 , 0. , 0.2 , 0. , 0.2 , 0. ], [0. , 0. , 0.33333333, 0.33333333, 0. , 0. ], [0. , 0. , 0. , 0. , 0. , 0. ]]) If we wanted an original W object, we can control that with the argument ``outSP``: >>> wc = libpysal.weights.w_clip(w1, w2, outSP=False) WARNING: there are 2 disconnected observations Island ids: [1, 5] >>> wc.full()[0] array([[0. , 0. , 0.33333333, 0.33333333, 0. , 0. ], [0. , 0. , 0. , 0. , 0. , 0. ], [0.2 , 0. , 0. , 0.2 , 0.2 , 0. ], [0.2 , 0. , 0.2 , 0. , 0.2 , 0. ], [0. , 0. , 0.33333333, 0.33333333, 0. , 0. ], [0. , 0. , 0. , 0. , 0. , 0. ]]) You can check they are actually the same: >>> wcs.sparse.toarray() == wc.full()[0] array([[ True, True, True, True, True, True], [ True, True, True, True, True, True], [ True, True, True, True, True, True], [ True, True, True, True, True, True], [ True, True, True, True, True, True], [ True, True, True, True, True, True]]) ''' from .util import WSP2W if not w1.id_order: w1.id_order = None id_order = w1.id_order if not isspmatrix_csr(w1): w1 = w1.sparse if not isspmatrix_csr(w2): w2 = w2.sparse w2.data = ones(w2.data.shape) wc = w1.multiply(w2) wc = WSP(wc, id_order=id_order) if not outSP: wc = WSP2W(wc, silence_warnings=silence_warnings) return wc
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 = 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) # 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
def test_add_dummy_feature_csr(): X = sp.csr_matrix([[1, 0], [0, 1], [0, 1]]) X = add_dummy_feature(X) assert_true(sp.isspmatrix_csr(X), X) assert_array_equal(X.toarray(), [[1, 1, 0], [1, 0, 1], [1, 0, 1]])
def classical_strength_of_connection(A, theta=0.0, norm='abs'): """Classical Strength Measure. Return a strength of connection matrix using the classical AMG measure An off-diagonal entry A[i,j] is a strong connection iff:: |A[i,j]| >= theta * max(|A[i,k]|), where k != i (norm='abs') -A[i,j] >= theta * max(-A[i,k]), where k != i (norm='min') Parameters ---------- A : csr_matrix or bsr_matrix Square, sparse matrix in CSR or BSR format theta : float Threshold parameter in [0,1]. norm: 'string' 'abs' : to use the absolute value, 'min' : to use the negative value (see above) Returns ------- S : csr_matrix Matrix graph defining strong connections. S[i,j]=1 if vertex i is strongly influenced by vertex j. See Also -------- symmetric_strength_of_connection : symmetric measure used in SA evolution_strength_of_connection : relaxation based strength measure Notes ----- - A symmetric A does not necessarily yield a symmetric strength matrix S - Calls C++ function classical_strength_of_connection - The version as implemented is designed form M-matrices. Trottenberg et al. use max A[i,k] over all negative entries, which is the same. A positive edge weight never indicates a strong connection. - See [2000BrHeMc]_ and [2001bTrOoSc]_ References ---------- .. [2000BrHeMc] Briggs, W. L., Henson, V. E., McCormick, S. F., "A multigrid tutorial", Second edition. Society for Industrial and Applied Mathematics (SIAM), Philadelphia, PA, 2000. xii+193 pp. .. [2001bTrOoSc] Trottenberg, U., Oosterlee, C. W., Schuller, A., "Multigrid", Academic Press, Inc., San Diego, CA, 2001. xvi+631 pp. Examples -------- >>> import numpy as np >>> from pyamg.gallery import stencil_grid >>> from pyamg.strength import classical_strength_of_connection >>> n=3 >>> stencil = np.array([[-1.0,-1.0,-1.0], ... [-1.0, 8.0,-1.0], ... [-1.0,-1.0,-1.0]]) >>> A = stencil_grid(stencil, (n,n), format='csr') >>> S = classical_strength_of_connection(A, 0.0) """ if sparse.isspmatrix_bsr(A): blocksize = A.blocksize[0] else: blocksize = 1 if not sparse.isspmatrix_csr(A): warn('Implicit conversion of A to csr', sparse.SparseEfficiencyWarning) A = sparse.csr_matrix(A) if (theta < 0 or theta > 1): raise ValueError('expected theta in [0,1]') Sp = np.empty_like(A.indptr) Sj = np.empty_like(A.indices) Sx = np.empty_like(A.data) if norm not in ('abs', 'min'): raise ValueError('Unknown norm') if norm == 'abs': amg_core.classical_strength_of_connection_abs(A.shape[0], theta, A.indptr, A.indices, A.data, Sp, Sj, Sx) elif norm == 'min': amg_core.classical_strength_of_connection_min(A.shape[0], theta, A.indptr, A.indices, A.data, Sp, Sj, Sx) S = sparse.csr_matrix((Sx, Sj, Sp), shape=A.shape) if blocksize > 1: S = amalgamate(S, blocksize) # Strength represents "distance", so take the magnitude S.data = np.abs(S.data) # Scale S by the largest magnitude entry in each row S = scale_rows_by_largest_entry(S) return S
def create(var, batch, seq_starts=None, device=None, read_only=False): ''' Creates a :class:`Value` object. Args: var (:class:`~cntk.ops.variables.Variable`): input variable into which ``batch`` is passed batch: batch input. It can be: * a single NumPy array denoting the full minibatch * a list of NumPy arrays or SciPy sparse CSR matrices seq_starts (list of `bool`s or None): if None, every sequence is treated as a new sequence. Otherwise, it is interpreted as a list of Booleans that tell whether a sequence is a new sequence (`True`) or a continuation of the sequence in the same slot of the previous minibatch (`False`) device (:class:`~cntk.device.DeviceDescriptor`, default None): device this value should be put on read_only (bool, default False): whether the data is read only Returns: :class:`Value` object. ''' if isinstance(batch, np.ndarray): # The outermost axis has to be Python list. If the user passes a # full minibatch as one NumPy array, we have to convert it. if batch.dtype == object: raise ValueError('dtype object is not supported. If this is a batch ' 'of sequences, you need to pass them as a pure-Python list ' 'of NumPy arrays') # FIXME if not seq_starts: directly pass it to Value constructor batch = list(np.atleast_1d(batch)) if not isinstance(batch, list): raise ValueError('batch has to be a list of NumPy arrays or ' 'SciPy CSR matrices') list_of_ndavs = [] # NDArrayViews are all created on CPU. The Value object later then will # move it to the requested device. cpu_dev = cpu() for sample in batch: if isinstance(sample, list): sample = np.asarray(sample, dtype=var.dtype) if sample.dtype != var.dtype: raise ValueError('could not convert sample data to ' 'NumPy array') if isinstance(sample, np.number): sample = np.asarray(sample) if not (isinstance(sample, np.ndarray) or sparse.issparse(sample)): raise ValueError('sample type "%s" is not supported. Please ' 'provide the data as a Python list of NumPy arrays ' 'or Scipy CSR matrices.'%type(sample)) if np.issubdtype(sample.dtype, int): sample = sample.astype(var.dtype) elif sample.dtype not in (np.float32, np.float64): raise ValueError('only integer, float32 and float64 are supported, ' 'you gave %s'%sample.dtype) else: sample = sample.astype(var.dtype) if isinstance(sample, np.ndarray): if not _is_c_contiguous(sample): warnings.warn('supplied data is not C contiguous; rearrange your data/computation to avoid this', RuntimeWarning) sample = np.ascontiguousarray(sample) ndav = _create_NDArrayView_from_NumPy(sample, cpu_dev) elif sparse.issparse(sample): if not sparse.isspmatrix_csr(sample): raise ValueError("only CSR is supported as of now. Please " "convert your data using 'tocsr()'") ndav = cntk_py.NDArrayView(sample.shape, sample.data, sample.indptr, sample.indices, cpu_dev, False) list_of_ndavs.append(ndav) return cntk_py.Value_create( _as_tuple(var.shape), list_of_ndavs, seq_starts or [], device or use_default_device(), read_only)
def reduce_symm_projector(p_full, dim, states_related_by_symm, print_results=False): """ Create an operator which projects onto a certain subspace which has definite transformation properties with respect to a given transformation operator. Typically this function is called on the output of the getCyclicProj function, which produces projop_full2full :param p_full: Needs to be a csc sparse matrix. Takes a state in the full space and projects it onto a state of a given symmetry. Returns a state in the initial basis. Does not reduce the size of the space. projOp_full2full * vector does not necessarily produce a normalized vector. :param dim: dimension of the irreducible representation in question :param bool print_results: Boolean indicating whether or not to print information to the terminal :return proj_full2reduced: sparse csr matrix. symm_proj is defined such that symm_proj*Op*symm_proj.transpose() is the operator Op in the projected subspace """ if print_results: tstart = time.perf_counter() if not sp.isspmatrix_csr(p_full): print("warning, projop_full2full was not csr. Converted it to csr.") p_full = p_full.tocsr() if not sp.isspmatrix_csr(states_related_by_symm): print("warning, projop_full2full was not csr. Converted it to csr.") states_related_by_symm = states_related_by_symm.tocsr() # round to avoid any finite precision issues p_full.data[np.abs(p_full.data) < 1e-10] = 0 p_full.eliminate_zeros() # remove any zero rows rows_noz = p_full.indptr[:-1] != p_full.indptr[1:] p_full = p_full[rows_noz, :] # find orthonormal basis for row space of matrix if dim == 1: # for each row, find first non-zero index first_nonzero_col = p_full.indices[p_full.indptr[:-1]] # We only need to check if the first indices are unique to find the unique rows. # For dim=1, if these are the same then so are the entire columns _, unique_indices = np.unique(first_nonzero_col, return_index=True) p_red = p_full[unique_indices, :] else: # can do for the full matrix, but then must be able to convert projector to dense # rank_full = np.linalg.matrix_rank(p_full.todense()) # u, s, vh = np.linalg.svd(p_full.todense(), full_matrices=True, compute_uv=True) # p_red_full = sp.csr_matrix(np.round(vh[:rank_full, :], 12)) # instead of SVD on entire matrix, we can split matrix into sets of states related by symmetry # only these states can transform into each other, so can do each of these sectors on its own states_related_by_symm = states_related_by_symm[rows_noz, :] # get identifier for which sets of states transform into one another under action of first_nonzero_col = states_related_by_symm.indices[states_related_by_symm.indptr[:-1]] # unique gives column indices of a unique set of basis vectors from which # all others can be obtained by applying symmetry operations unique, unique_indices, unique_inverse, counts = np.unique(first_nonzero_col, return_index=True, return_inverse=True, return_counts=True) # first_indices = unique[unique_inverse] # unique = first_indices[unique_indices]. # get collection of all rows that related by symmetry unique_inv_sorted = np.argsort(unique_inverse) # construct reduced projector matrix # maximum rank, but real rank can be less than this p_red = sp.lil_matrix((p_full.shape)) p_row_counter = 0 inv_counter = 0 # loop over subspaces represented by for ii in range(len(unique)): # all column indices = unique_inv_sorted[inv_counter : inv_counter + counts[ii]] # non-zero rows for this the first column vector (which will be identical for the other related vectors) cols = states_related_by_symm.indices[states_related_by_symm.indptr[unique_inv_sorted[inv_counter]]: states_related_by_symm.indptr[unique_inv_sorted[inv_counter] + 1]] # get relevant matrices, only keep nonzero rows and columns for this subpsace ccols, rrows = np.meshgrid(cols, unique_inv_sorted[inv_counter : inv_counter + counts[ii]]) mat = p_full[rrows, ccols].todense() rank = np.linalg.matrix_rank(mat) u, s, vh = np.linalg.svd(mat, full_matrices=True, compute_uv=True) mat_red = np.round(vh[:rank, :], 15) # put these back in the correct rows for the final projector ccols_out, rrows_out = np.meshgrid(cols, np.arange(p_row_counter, p_row_counter + rank)) p_red[rrows_out, ccols_out] = mat_red # advance counters inv_counter += counts[ii] p_row_counter += rank p_red = p_red[:p_row_counter, :].tocsr() # normalize each row norms = np.sqrt(np.asarray(p_red.multiply(p_red.conj()).sum(axis=1))).flatten() p_red = sp.diags(np.reciprocal(norms), 0, format="csr") * p_red if print_results: tend = time.perf_counter() print("Finding projector took %0.2f s" % (tend - tstart)) return p_red
def test_displace_type(): "Operator CSR Type: displace" op = displace(5, 0.1) assert_equal(isspmatrix_csr(op.data), True)
def _document_frequency(X): """Count the number of non-zero values for each feature in sparse X.""" if sp.isspmatrix_csr(X): return bincount(X.indices, minlength=X.shape[1]) else: return np.diff(sp.csc_matrix(X, copy=False).indptr)
def test_qdiags_type(): "Operator CSR Type: qdiags" op = qdiags(np.sqrt(range(1, 4)), 1) assert_equal(isspmatrix_csr(op.data), True)
def propagationKernel(A, l, gr_id, h_max, w, p, ktype=None, SUM=True, VIS=False, showEachStep=False): ''' Propagation kernel for graphs as described in: Neumann, M., Patricia, N., Garnett, R., Kersting, K.: Efficient Graph Kernels by Randomization. In: P.A. Flach, T.D. Bie, N. Cristianini (eds.) ECML/PKDD, Notes in Computer Science, vol. 7523, pp. 378-393. Springer (2012). :param A: adjacency matrix (num_nodes x num_nodes) :param l: label array (num_nodes x 1); values [1,...,k] or -1 for unlabeled nodes OR label array (num_nodes x num_labels); values [0,1], unlabeled nodes have only 0 entries :param gr_id: graph indicator array (num_nodes x 1); values [0,..,n] :param h_max: number of iterations :param w: bin widths parameter :param p: distance ('tv', 'hellinger', 'L1', 'L2') :param ktype: type of propagation kernel ['diffusion', 'label_propagation', 'label_spreading', 'belief_propagation'] :return: kernel matrix ''' # ToDO: SPLIT Varible label array and label probability # CAUTION: number of labels (k) > 1 !!! #=========================================================================== # ## Propagation Kernel COMPUTATION #=========================================================================== num_graphs = gr_id.max().astype(int) num_nodes = A.shape[0] if l.shape[1] == 1: num_labels = l.max().astype(int) else: num_labels = l.shape[1] #=========================================================================== # ## INITIALIZATION #=========================================================================== ## CHECK and ADJUST sparseness if not spsp.issparse(A): A = spsp.csr_matrix(A) else: if not spsp.isspmatrix_csr(A): A = A.tocsr() # MAKE sure A is float! A = A.astype(float) ## INITIALIZE kernel matrix K = np.ndarray(shape=(num_graphs, num_graphs, h_max + 1), dtype=float) ## INITIALIZE label probabilities of labeled nodes (num_nodes x num_labels) if l.shape[1] == 1: lab_prob = np.zeros((num_nodes, num_labels), dtype=np.float64) for i in range(num_nodes): if l[i, 0] > 0: lab_prob[i, l[i, 0] - 1] = 1 else: lab_prob = l if spsp.issparse(lab_prob): lab_prob = lab_prob.todense() lab_orig = lab_prob.copy() # lab_orig is the orignal label information ## GET indices of labeled and unlabeled nodes idx_unlab = np.where(np.max(lab_prob, axis=1) != 1)[0] idx_all = np.array(np.arange(0, A.shape[0]), ndmin=2) idx = np.array(np.setdiff1d(idx_all, idx_unlab), ndmin=2) ## INITIALIZE unlabeled/uninitialized nodes UNIFORMLY idx_unif = np.where(np.sum(lab_prob, axis=1) == 0)[0] if idx_unif.shape[0] != 0: lab_prob[idx_unif, :] = old_div(1., lab_prob.shape[1]) ## row normalize A -> transition matrix T if (ktype == 'label_propagation') or (ktype == 'label_diffusion'): row_sums = np.array(A.sum(axis=1))[:, 0] T = A.copy() T.data /= row_sums[A.nonzero()[0]] # so A and T are sparse matrix #=========================================================================== # ## PROPAGATION KERNEL ITERATIONS #=========================================================================== for h in range(h_max + 1): print('ITERATION: ', h) if h > 0: ## LABEL UPDATE if showEachStep: print('...computing LABEL UPDATE') if ktype == 'label_propagation': lab_prob[idx, :] = lab_orig[ idx, :] # PUSH BACK original LABELS lab_prob = T * lab_prob elif ktype == 'label_diffusion': lab_prob = T * lab_prob elif ktype == 'label_spreading': # S = D^(-1/2)*W*D^(-1/2) # y(t+1) = alpha*S*y(t)+(1-alpha)*y(0) alpha = 0.8 # compute S diag = np.array(A.sum(axis=1)).T**(old_div(-1, 2)) D = spsp.lil_matrix((A.shape[0], A.shape[1]), dtype=float) # D.setdiag(diag[0, :]) D = D.tocsr() S = D * A * D lab_prob = np.dot( (alpha * S.todense()), lab_prob) + (1 - alpha) * lab_orig ## COMPUTE hashvalues if showEachStep: print('...computing hashvalues') # determine path to take depending on chosen distance use_cauchy = (p == 'L1') or (p == 'tv') take_sqrt = (p == 'hellinger') if take_sqrt: lab_prob = np.sqrt(lab_prob) # generate random projection vector v = np.random.normal(size=(lab_prob.shape[1], 1)) if use_cauchy: # if X, Y are N(0, 1), then X / Y has a standard Cauchy distribution v /= np.random.normal(size=(lab_prob.shape[1], 1)) # random offset b = w * np.random.rand() # compute hashes # hashLabels is a Vector with length: number of nodes (hashvalue for respective node) hashLabels = old_div((np.dot(lab_prob, v) + b), w) hashLabels = np.floor(hashLabels) # take floor uniqueHash, hashLabels = np.unique( hashLabels, return_inverse=True) # map to consecutive integer from 0 ## COMPUTE kernel contribution if showEachStep: print('...computing KERNEL contribution') # aggregate counts on graphs # counts is a matrix: number of graphs x number of hashlabels num_bins = len(uniqueHash) counts = np.zeros((num_graphs, num_bins)) # init counts matrix # accumulate counts of hash labels for i in range(num_nodes): counts[(gr_id[i, 0] - 1), hashLabels[i]] += 1 # compute base kernel (here: LINEAR kernel) K_h = np.dot(counts, counts.T) ## SUM kernel contributions if SUM: if h == 0: K[:, :, h] = K_h else: K[:, :, h] = K[:, :, h - 1] + K_h else: K[:, :, h] = K_h if showEachStep: print(K[:, :, h]) ## VISUALIZE KERNELS if VIS: for h in range(h_max + 1): K_h = K[:, :, h] plt.figure() plt.title('height:' + str(h)) imgplot = plt.imshow(K_h) imgplot.set_interpolation('nearest') plt.colorbar() plt.show() return K
def test_position_type(): "Operator CSR Type: position" op = position(5) assert_equal(isspmatrix_csr(op.data), True)
def test_phase_type(): "Operator CSR Type: phase" op = phase(5, np.pi) assert_equal(isspmatrix_csr(op.data), True)
def jacobi(A, x, b, iterations=1, omega=1.0): """Perform Jacobi iteration on the linear system Ax=b Parameters ---------- A : csr_matrix Sparse NxN matrix x : ndarray Approximate solution (length N) b : ndarray Right-hand side (length N) iterations : int Number of iterations to perform omega : scalar Damping parameter Returns ------- Nothing, x will be modified in place. Examples -------- >>> # Use Jacobi as a Stand-Alone Solver >>> from pyamg.relaxation.relaxation.relaxation import jacobi >>> from pyamg.gallery import poisson >>> from pyamg.util.linalg import norm >>> import numpy as np >>> A = poisson((10,10), format='csr') >>> x0 = np.zeros((A.shape[0],1)) >>> b = np.ones((A.shape[0],1)) >>> jacobi(A, x0, b, iterations=10, omega=1.0) >>> print norm(b-A*x0) 5.83475132751 >>> # >>> # Use Jacobi as the Multigrid Smoother >>> from pyamg import smoothed_aggregation_solver >>> sa = smoothed_aggregation_solver(A, B=np.ones((A.shape[0],1)), ... coarse_solver='pinv2', max_coarse=50, ... presmoother=('jacobi', {'omega': 4.0/3.0, 'iterations' : 2}), ... postsmoother=('jacobi', {'omega': 4.0/3.0, 'iterations' : 2})) >>> x0=np.zeros((A.shape[0],1)) >>> residuals=[] >>> x = sa.solve(b, x0=x0, tol=1e-8, residuals=residuals) """ A, x, b = make_system(A, x, b, formats=['csr', 'bsr']) sweep = slice(None) (row_start, row_stop, row_step) = sweep.indices(A.shape[0]) if (row_stop - row_start) * row_step <= 0: # no work to do return temp = np.empty_like(x) # Create uniform type, convert possibly complex scalars to length 1 arrays [omega] = type_prep(A.dtype, [omega]) if sparse.isspmatrix_csr(A): for iter in range(iterations): amg_core.jacobi(A.indptr, A.indices, A.data, x, b, temp, row_start, row_stop, row_step, omega) else: R, C = A.blocksize if R != C: raise ValueError('BSR blocks must be square') row_start = int(row_start / R) row_stop = int(row_stop / R) for iter in range(iterations): amg_core.bsr_jacobi(A.indptr, A.indices, np.ravel(A.data), x, b, temp, row_start, row_stop, row_step, R, omega)
def test_destroy_type(): "Operator CSR Type: destroy" op = destroy(5) assert_equal(isspmatrix_csr(op.data), True)
def spsolve(A, b, permc_spec=None, use_umfpack=True): """Solve the sparse linear system Ax=b, where b may be a vector or a matrix. Parameters ---------- A : ndarray or sparse matrix The square matrix A will be converted into CSC or CSR form b : ndarray or sparse matrix The matrix or vector representing the right hand side of the equation. If a vector, b.size must be (n,) or (n, 1) permc_spec : str, optional How to permute the columns of the matrix for sparsity preservation. (default: 'COLAMD') - ``NATURAL``: natural ordering. - ``MMD_ATA``: minimum degree ordering on the structure of A^T A. - ``MMD_AT_PLUS_A``: minimum degree ordering on the structure of A^T+A. - ``COLAMD``: approximate minimum degree column ordering use_umfpack : bool (optional) if True (default) then use umfpack for the solution. This is only referenced if b is a vector and ``scikit-umfpack`` is installed. Returns ------- x : ndarray or sparse matrix the solution of the sparse linear equation. If b is a vector, then x is a vector of size A.shape[1] If b is a matrix, then x is a matrix of size (A.shape[1], b.shape[1]) Notes ----- For solving the matrix expression AX = B, this solver assumes the resulting matrix X is sparse, as is often the case for very sparse inputs. If the resulting X is dense, the construction of this sparse result will be relatively expensive. In that case, consider converting A to a dense matrix and using scipy.linalg.solve or its variants. """ if not (isspmatrix_csc(A) or isspmatrix_csr(A)): A = csc_matrix(A) warn('spsolve requires A be CSC or CSR matrix format', SparseEfficiencyWarning) # b is a vector only if b have shape (n,) or (n, 1) b_is_sparse = isspmatrix(b) if not b_is_sparse: b = asarray(b) b_is_vector = ((b.ndim == 1) or (b.ndim == 2 and b.shape[1] == 1)) A.sort_indices() A = A.asfptype() # upcast to a floating point format # validate input shapes M, N = A.shape if (M != N): raise ValueError("matrix must be square (has shape %s)" % ((M, N),)) if M != b.shape[0]: raise ValueError("matrix - rhs dimension mismatch (%s - %s)" % (A.shape, b.shape[0])) use_umfpack = use_umfpack and useUmfpack if b_is_vector and use_umfpack: if b_is_sparse: b_vec = b.toarray() else: b_vec = b b_vec = asarray(b_vec, dtype=A.dtype).ravel() if noScikit: raise RuntimeError('Scikits.umfpack not installed.') if A.dtype.char not in 'dD': raise ValueError("convert matrix data to double, please, using" " .astype(), or set linsolve.useUmfpack = False") family = {'d': 'di', 'D': 'zi'} umf = umfpack.UmfpackContext(family[A.dtype.char]) x = umf.linsolve(umfpack.UMFPACK_A, A, b_vec, autoTranspose=True) else: if b_is_vector and b_is_sparse: b = b.toarray() b_is_sparse = False if not b_is_sparse: if isspmatrix_csc(A): flag = 1 # CSC format else: flag = 0 # CSR format options = dict(ColPerm=permc_spec) x, info = _superlu.gssv(N, A.nnz, A.data, A.indices, A.indptr, b, flag, options=options) if info != 0: warn("Matrix is exactly singular", MatrixRankWarning) x.fill(np.nan) if b_is_vector: x = x.ravel() else: # b is sparse Afactsolve = factorized(A) if not isspmatrix_csc(b): warn('spsolve is more efficient when sparse b ' 'is in the CSC matrix format', SparseEfficiencyWarning) b = csc_matrix(b) # Create a sparse output matrix by repeatedly applying # the sparse factorization to solve columns of b. data_segs = [] row_segs = [] col_segs = [] for j in range(b.shape[1]): bj = b[:, j].A.ravel() xj = Afactsolve(bj) w = np.flatnonzero(xj) segment_length = w.shape[0] row_segs.append(w) col_segs.append(np.ones(segment_length, dtype=int)*j) data_segs.append(np.asarray(xj[w], dtype=A.dtype)) sparse_data = np.concatenate(data_segs) sparse_row = np.concatenate(row_segs) sparse_col = np.concatenate(col_segs) x = A.__class__((sparse_data, (sparse_row, sparse_col)), shape=b.shape, dtype=A.dtype) return x
def test_20news_vectorized(): try: datasets.fetch_20newsgroups(subset='all', download_if_missing=False) except IOError: raise SkipTest("Download 20 newsgroups to run this test") # test subset = train bunch = datasets.fetch_20newsgroups_vectorized(subset="train") assert_true(sp.isspmatrix_csr(bunch.data)) assert_equal(bunch.data.shape, (11314, 130107)) assert_equal(bunch.target.shape[0], 11314) assert_equal(bunch.data.dtype, np.float64) # test subset = test bunch = datasets.fetch_20newsgroups_vectorized(subset="test") assert_true(sp.isspmatrix_csr(bunch.data)) assert_equal(bunch.data.shape, (7532, 130107)) assert_equal(bunch.target.shape[0], 7532) assert_equal(bunch.data.dtype, np.float64) # test return_X_y option fetch_func = partial(datasets.fetch_20newsgroups_vectorized, subset='test') check_return_X_y(bunch, fetch_func) # test subset = all bunch = datasets.fetch_20newsgroups_vectorized(subset='all') assert_true(sp.isspmatrix_csr(bunch.data)) assert_equal(bunch.data.shape, (11314 + 7532, 130107)) assert_equal(bunch.target.shape[0], 11314 + 7532) assert_equal(bunch.data.dtype, np.float64)