def matrix_exponential(G_nn, dlt): """Computes the matrix exponential of an antihermitian operator U = exp(i*dlt*G) G_nn: ndarray anti-hermitian (skew-symmetric) matrix. dlt: float scaling factor for G_nn. """ ndim = G_nn.shape[1] w_n = np.zeros((ndim), dtype=float) V_nn = np.zeros((ndim, ndim), dtype=complex) O_nn = np.zeros((ndim, ndim), dtype=complex) if G_nn.dtype == complex: V_nn = 1j * G_nn.real - G_nn.imag else: V_nn = 1j * G_nn.real diagonalize(V_nn, w_n) # O_nn = np.diag(np.exp(1j * dlt * w_n)) # if G_nn.dtype == complex: U_nn = np.dot(V_nn.T.conj(), np.dot(O_nn, V_nn)).copy() else: U_nn = np.dot(V_nn.T.conj(), np.dot(O_nn, V_nn)).real.copy() # return U_nn
def diagonalize(self, istart=None, jend=None, energy_range=None): """Evaluate Eigenvectors and Eigenvalues:""" map, kss = self.get_map(istart, jend, energy_range) nij = len(kss) if map is None: ApB = self.ApB.copy() AmB = self.AmB.copy() nij = len(kss) else: ApB = np.empty((nij, nij)) AmB = np.empty((nij, nij)) for ij in range(nij): for kq in range(nij): ApB[ij,kq] = self.ApB[map[ij],map[kq]] AmB[ij,kq] = self.AmB[map[ij],map[kq]] # the occupation matrix C = np.empty((nij,)) for ij in range(nij): C[ij] = 1. / kss[ij].fij S = C * inv(AmB) * C S = sqrt_matrix(inv(S).copy()) # get Omega matrix M = np.zeros(ApB.shape) gemm(1.0, ApB, S, 0.0, M) self.eigenvectors = np.zeros(ApB.shape) gemm(1.0, S, M, 0.0, self.eigenvectors) self.eigenvalues = np.zeros((len(kss))) self.kss = kss diagonalize(self.eigenvectors, self.eigenvalues)
def matrix_exponential(G_nn, dlt): """Computes the matrix exponential of an antihermitian operator U = exp(i*dlt*G) G_nn: ndarray anti-hermitian (skew-symmetric) matrix. dlt: float scaling factor for G_nn. """ ndim = G_nn.shape[1] w_n = np.zeros((ndim), dtype=float) V_nn = np.zeros((ndim, ndim), dtype=complex) O_nn = np.zeros((ndim, ndim), dtype=complex) if G_nn.dtype==complex: V_nn = 1j*G_nn.real - G_nn.imag else: V_nn = 1j*G_nn.real diagonalize(V_nn, w_n) # O_nn = np.diag(np.exp(1j*dlt*w_n)) # if G_nn.dtype==complex: U_nn = np.dot(V_nn.T.conj(),np.dot(O_nn, V_nn)).copy() else: U_nn = np.dot(V_nn.T.conj(),np.dot(O_nn, V_nn)).real.copy() # return U_nn
def diagonalize(self, H_sS): if self.coupling: # Non-Hermitian matrix can only use linalg.eig self.printtxt('Use numpy.linalg.eig') H_SS = np.zeros((self.nS, self.nS), dtype=complex) if self.nS % world.size == 0: world.all_gather(H_sS, H_SS) else: H_SS = gatherv(H_sS) self.w_S, self.v_SS = np.linalg.eig(H_SS) self.par_save('v_SS', 'v_SS', self.v_SS[self.nS_start:self.nS_end, :].copy()) else: if world.size == 1: self.printtxt('Use lapack.') from gpaw.utilities.lapack import diagonalize self.w_S = np.zeros(self.nS) H_SS = H_sS diagonalize(H_SS, self.w_S) self.v_SS = H_SS.conj() # eigenvectors in the rows, transposed later else: self.printtxt('Use scalapack') self.w_S, self.v_sS = self.scalapack_diagonalize(H_sS) self.v_SS = self.v_sS # just use the same name self.par_save('v_SS', 'v_SS', self.v_SS) return
def ortho(W_nn, maxerr=1E-10): """ Orthogonalizes the column vectors of a matrix by Symmetric Loewdin orthogonalization W_nn: ndarray unorthonormal matrix. maxerr: float maximum error for using explicit diagonalization. """ ndim = np.shape(W_nn)[1] # overlap matrix O_nn = np.dot(W_nn, W_nn.T.conj()) # check error in orthonormality err = np.sum(np.abs(O_nn - np.eye(ndim))) if (err < maxerr): # perturbative Symmetric-Loewdin X_nn = 1.5 * np.eye(ndim) - 0.5 * O_nn else: # diagonalization n_n = np.zeros(ndim, dtype=float) diagonalize(O_nn, n_n) U_nn = O_nn.T.conj().copy() nsqrt_n = np.diag(1.0 / np.sqrt(n_n)) X_nn = np.dot(np.dot(U_nn, nsqrt_n), U_nn.T.conj()) # apply orthonormalizing transformation O_nn = np.dot(X_nn, W_nn) return O_nn
def diagonalize(self, H_sS): if self.coupling: # Non-Hermitian matrix can only use linalg.eig self.printtxt('Use numpy.linalg.eig') H_SS = np.zeros((self.nS, self.nS), dtype=complex) if self.nS % world.size == 0: world.all_gather(H_sS, H_SS) else: H_SS = gatherv(H_sS) self.w_S, self.v_SS = np.linalg.eig(H_SS) self.par_save('v_SS', 'v_SS', self.v_SS[self.nS_start:self.nS_end, :].copy()) else: if world.size == 1: self.printtxt('Use lapack.') from gpaw.utilities.lapack import diagonalize self.w_S = np.zeros(self.nS) H_SS = H_sS diagonalize(H_SS, self.w_S) self.v_SS = H_SS.conj( ) # eigenvectors in the rows, transposed later else: self.printtxt('Use scalapack') self.w_S, self.v_sS = self.scalapack_diagonalize(H_sS) self.v_SS = self.v_sS # just use the same name self.par_save('v_SS', 'v_SS', self.v_SS) return
def diagonalize(self, istart=None, jend=None, energy_range=None, TDA=False): """Evaluate Eigenvectors and Eigenvalues""" ApB, AmB = self.map(istart, jend, energy_range) nij = len(self.kss) if TDA: # Tamm-Dancoff approximation (B=0) self.eigenvectors = 0.5 * (ApB + AmB) eigenvalues = np.zeros((nij)) diagonalize(self.eigenvectors, eigenvalues) self.eigenvalues = eigenvalues**2 else: # the occupation matrix C = np.empty((nij, )) for ij in range(nij): C[ij] = 1. / self.kss[ij].fij S = C * inv(AmB) * C S = sqrt_matrix(inv(S).copy()) # get Omega matrix M = np.zeros(ApB.shape) gemm(1.0, ApB, S, 0.0, M) self.eigenvectors = np.zeros(ApB.shape) gemm(1.0, S, M, 0.0, self.eigenvectors) self.eigenvalues = np.zeros((nij)) diagonalize(self.eigenvectors, self.eigenvalues)
def diagonalize(self, istart=None, jend=None, energy_range=None, TDA=False): """Evaluate Eigenvectors and Eigenvalues""" ApB, AmB = self.map(istart, jend, energy_range) nij = len(self.kss) if TDA: # Tamm-Dancoff approximation (B=0) self.eigenvectors = 0.5 * (ApB + AmB) eigenvalues = np.zeros((nij)) diagonalize(self.eigenvectors, eigenvalues) self.eigenvalues = eigenvalues ** 2 else: # the occupation matrix C = np.empty((nij,)) for ij in range(nij): C[ij] = 1.0 / self.kss[ij].fij S = C * inv(AmB) * C S = sqrt_matrix(inv(S).copy()) # get Omega matrix M = np.zeros(ApB.shape) gemm(1.0, ApB, S, 0.0, M) self.eigenvectors = np.zeros(ApB.shape) gemm(1.0, S, M, 0.0, self.eigenvectors) self.eigenvalues = np.zeros((nij)) diagonalize(self.eigenvectors, self.eigenvalues)
def diagonalize(self): print('Diagonalizing Hamiltonian', file=self.fd) """The t and T represent local and global eigenstates indices respectively """ # Non-Hermitian matrix can only use linalg.eig if not self.td: print(' Using numpy.linalg.eig...', file=self.fd) print(' Eliminated %s pair orbitals' % len(self.excludef_S), file=self.fd) self.H_SS = self.collect_A_SS(self.H_sS) self.w_T = np.zeros(self.nS - len(self.excludef_S), complex) if world.rank == 0: self.H_SS = np.delete(self.H_SS, self.excludef_S, axis=0) self.H_SS = np.delete(self.H_SS, self.excludef_S, axis=1) self.w_T, self.v_ST = np.linalg.eig(self.H_SS) world.broadcast(self.w_T, 0) self.df_S = np.delete(self.df_S, self.excludef_S) self.rhoG0_S = np.delete(self.rhoG0_S, self.excludef_S) # Here the eigenvectors are returned as complex conjugated rows else: if world.size == 1: print(' Using lapack...', file=self.fd) from gpaw.utilities.lapack import diagonalize self.w_T = np.zeros(self.nS) diagonalize(self.H_sS, self.w_T) self.v_St = self.H_sS.conj().T else: print(' Using scalapack...', file=self.fd) nS = self.nS ns = -(-self.kd.nbzkpts // world.size) * (self.nv * self.nc * self.spins * (self.spinors + 1)**2) grid = BlacsGrid(world, world.size, 1) desc = grid.new_descriptor(nS, nS, ns, nS) desc2 = grid.new_descriptor(nS, nS, 2, 2) H_tmp = desc2.zeros(dtype=complex) r = Redistributor(world, desc, desc2) r.redistribute(self.H_sS, H_tmp) self.w_T = np.empty(nS) v_tmp = desc2.empty(dtype=complex) desc2.diagonalize_dc(H_tmp, v_tmp, self.w_T) r = Redistributor(grid.comm, desc2, desc) self.v_St = desc.zeros(dtype=complex) r.redistribute(v_tmp, self.v_St) self.v_St = self.v_St.conj().T if self.write_v and self.td: # Cannot use par_save without td self.par_save('v_TS.ulm', 'v_TS', self.v_St.T) return
def main(nbands=1000, mprocs=2, mb=64): # Set-up BlacsGrud grid = BlacsGrid(world, mprocs, mprocs) # Create descriptor nndesc = grid.new_descriptor(nbands, nbands, mb, mb) H_nn = nndesc.empty( dtype=float) # outside the BlacsGrid these are size zero C_nn = nndesc.empty( dtype=float) # outside the BlacsGrid these are size zero eps_N = np.empty((nbands), dtype=float) # replicated array on all MPI tasks # Fill ScaLAPACK array alpha = 0.1 # off-diagonal beta = 75.0 # diagonal uplo = 'L' # lower-triangular scalapack_set(nndesc, H_nn, alpha, beta, uplo) scalapack_zero(nndesc, H_nn, switch_uplo[uplo]) t1 = time() # either interface will work, we recommend use the latter interface # scalapack_diagonalize_dc(nndesc, H_nn.copy(), C_nn, eps_N, 'L') nndesc.diagonalize_dc(H_nn.copy(), C_nn, eps_N) t2 = time() world.broadcast(eps_N, 0) # all MPI tasks now have eps_N world.barrier() # wait for everyone to finish if rank == 0: print('ScaLAPACK diagonalize_dc', t2 - t1) # Create replicated NumPy array diagonal = np.eye(nbands, dtype=float) offdiagonal = np.tril(np.ones((nbands, nbands)), -1) H0 = beta * diagonal + alpha * offdiagonal E0 = np.empty((nbands), dtype=float) t1 = time() diagonalize(H0, E0) t2 = time() if rank == 0: print('LAPACK diagonalize', t2 - t1) delta = abs(E0 - eps_N).max() if rank == 0: print(delta) assert delta < tol
def diagonalize(self, istart=None, jend=None, energy_range=None): """Evaluate Eigenvectors and Eigenvalues:""" map, kss = self.get_map(istart, jend, energy_range) nij = len(kss) if map is None: evec = self.full.copy() else: evec = np.zeros((nij,nij)) for ij in range(nij): for kq in range(nij): evec[ij,kq] = self.full[map[ij],map[kq]] self.eigenvectors = evec self.eigenvalues = np.zeros((len(kss))) self.kss = kss diagonalize(self.eigenvectors, self.eigenvalues)
def diagonalize(self, istart=None, jend=None, energy_range=None): """Evaluate Eigenvectors and Eigenvalues:""" map, kss = self.get_map(istart, jend, energy_range) nij = len(kss) if map is None: evec = self.full.copy() else: evec = np.zeros((nij, nij)) for ij in range(nij): for kq in range(nij): evec[ij, kq] = self.full[map[ij], map[kq]] self.eigenvectors = evec self.eigenvalues = np.zeros((len(kss))) self.kss = kss diagonalize(self.eigenvectors, self.eigenvalues)
def main(nbands=1000, mprocs=2, mb=64): # Set-up BlacsGrud grid = BlacsGrid(world, mprocs, mprocs) # Create descriptor nndesc = grid.new_descriptor(nbands, nbands, mb, mb) H_nn = nndesc.empty(dtype=float) # outside the BlacsGrid these are size zero C_nn = nndesc.empty(dtype=float) # outside the BlacsGrid these are size zero eps_N = np.empty((nbands), dtype=float) # replicated array on all MPI tasks # Fill ScaLAPACK array alpha = 0.1 # off-diagonal beta = 75.0 # diagonal uplo = 'L' # lower-triangular scalapack_set(nndesc, H_nn, alpha, beta, uplo) scalapack_zero(nndesc, H_nn, switch_uplo[uplo]) t1 = time() # either interface will work, we recommend use the latter interface # scalapack_diagonalize_dc(nndesc, H_nn.copy(), C_nn, eps_N, 'L') nndesc.diagonalize_dc(H_nn.copy(), C_nn, eps_N) t2 = time() world.broadcast(eps_N, 0) # all MPI tasks now have eps_N world.barrier() # wait for everyone to finish if rank == 0: print('ScaLAPACK diagonalize_dc', t2-t1) # Create replicated NumPy array diagonal = np.eye(nbands,dtype=float) offdiagonal = np.tril(np.ones((nbands,nbands)), -1) H0 = beta*diagonal + alpha*offdiagonal E0 = np.empty((nbands), dtype=float) t1 = time() diagonalize(H0,E0) t2 = time() if rank == 0: print('LAPACK diagonalize', t2-t1) delta = abs(E0-eps_N).max() if rank == 0: print(delta) assert delta < tol
def diagonalize(self, istart=None, jend=None, energy_range=None, TDA=False): """Evaluate Eigenvectors and Eigenvalues:""" if TDA: raise NotImplementedError map, kss = self.get_map(istart, jend, energy_range) nij = len(kss) if map is None: evec = self.full.copy() else: evec = np.zeros((nij,nij)) for ij in range(nij): for kq in range(nij): evec[ij,kq] = self.full[map[ij],map[kq]] assert(len(evec) > 0) self.eigenvectors = evec self.eigenvalues = np.zeros((len(kss))) self.kss = kss diagonalize(self.eigenvectors, self.eigenvalues)
def main(i,seed=42,dtype=float): if (dtype==complex): epsilon = 0.1j else: epsilon = 0.1 x = i + 1 N = x*100 print "N =",N H0 = np.zeros((N,N),dtype=dtype) + gen.rand(*(N,N)) H1 = H0 + epsilon*np.tri(N,N, k=-1) W0 = np.zeros((N)) Z0 = np.zeros_like(H0) t0 = time() diagonalize(H1, W0) t1 = time() - t0 print "diagonalize", t1 t2 = time() diagonalize_mr3(H1, W0, Z0) t3 = time() - t2 print "diagonalize_mr3",t3 # diagonalize_mr3 must be faster than diagonalize assert(t3 < t1)
def main(i, seed=42, dtype=float): if (dtype == complex): epsilon = 0.1j else: epsilon = 0.1 x = i + 1 N = x * 100 print "N =", N H0 = np.zeros((N, N), dtype=dtype) + gen.rand(*(N, N)) H1 = H0 + epsilon * np.tri(N, N, k=-1) W0 = np.zeros((N)) Z0 = np.zeros_like(H0) t0 = time() diagonalize(H1, W0) t1 = time() - t0 print "diagonalize", t1 t2 = time() diagonalize_mr3(H1, W0, Z0) t3 = time() - t2 print "diagonalize_mr3", t3 # diagonalize_mr3 must be faster than diagonalize assert (t3 < t1)
def diagonalize(self, istart=None, jend=None, energy_range=None, TDA=False): """Evaluate Eigenvectors and Eigenvalues:""" if TDA: raise NotImplementedError map, kss = self.get_map(istart, jend, energy_range) nij = len(kss) if map is None: evec = self.full.copy() else: evec = np.zeros((nij, nij)) for ij in range(nij): for kq in range(nij): evec[ij, kq] = self.full[map[ij], map[kq]] assert(len(evec) > 0) self.eigenvectors = evec self.eigenvalues = np.zeros((len(kss))) self.kss = kss diagonalize(self.eigenvectors, self.eigenvalues)
def ortho(W_nn, maxerr=1E-10): """ Orthogonalizes the column vectors of a matrix by Symmetric Loewdin orthogonalization W_nn: ndarray unorthonormal matrix. maxerr: float maximum error for using explicit diagonalization. """ ndim = np.shape(W_nn)[1] # # overlap matrix O_nn = np.dot(W_nn, W_nn.T.conj()) # # check error in orthonormality err = np.sum(np.abs(O_nn - np.eye(ndim))) if (err < maxerr): # # perturbative Symmetric-Loewdin X_nn= 1.5*np.eye(ndim) - 0.5*O_nn else: # # diagonalization n_n = np.zeros(ndim, dtype=float) diagonalize(O_nn, n_n) U_nn = O_nn.T.conj().copy() nsqrt_n = np.diag(1.0/np.sqrt(n_n)) X_nn = np.dot(np.dot(U_nn, nsqrt_n), U_nn.T.conj()) # # apply orthonormalizing transformation O_nn = np.dot(X_nn, W_nn) return O_nn
return eps, B elif nodes == 'all': if rank != 0: B = np.zeros((N, N)) world.broadcast(B, 0) return eps, B # generate a matrix N = 512 A = np.arange(N**2, dtype=float).reshape(N, N) for i in range(N): for j in range(i, N): A[i, j] = A[j, i] # diagonalize eps, B = scal_diagonalize(A) check = 1 if check and rank == 0: # check whether it gives the same result with lapack eps1 = np.zeros(N) diagonalize(A, eps1) assert np.abs(eps - eps1).sum() < 1e-6 for i in range(N // size): # the eigenvectors are row of the matrix, it can be differ by a minus sign. if np.abs(A[i, :] - B[i, :]).sum() > 1e-6: if np.abs(A[i, :] + B[i, :]).sum() > 1e-6: raise ValueError('Check !')
def main(N=72, seed=42, mprocs=2, nprocs=2, dtype=float): gen = np.random.RandomState(seed) grid = BlacsGrid(world, mprocs, nprocs) if (dtype == complex): epsilon = 1.0j else: epsilon = 0.0 # Create descriptors for matrices on master: glob = grid.new_descriptor(N, N, N, N) # print globA.asarray() # Populate matrices local to master: H0 = glob.zeros(dtype=dtype) + gen.rand(*glob.shape) S0 = glob.zeros(dtype=dtype) + gen.rand(*glob.shape) C0 = glob.empty(dtype=dtype) if rank == 0: # Complex case must have real numbers on the diagonal. # We make a simple complex Hermitian matrix below. H0 = H0 + epsilon * (0.1 * np.tri(N, N, k=-N // nprocs) + 0.3 * np.tri(N, N, k=-1)) S0 = S0 + epsilon * (0.2 * np.tri(N, N, k=-N // nprocs) + 0.4 * np.tri(N, N, k=-1)) # Make matrices symmetric rk(1.0, H0.copy(), 0.0, H0) rk(1.0, S0.copy(), 0.0, S0) # Overlap matrix must be semi-positive definite S0 = S0 + 50.0 * np.eye(N, N, 0) # Hamiltonian is usually diagonally dominant H0 = H0 + 75.0 * np.eye(N, N, 0) C0 = S0.copy() S0_inv = S0.copy() # Local result matrices W0 = np.empty((N), dtype=float) W0_g = np.empty((N), dtype=float) # Calculate eigenvalues / other serial results if rank == 0: diagonalize(H0.copy(), W0) general_diagonalize(H0.copy(), W0_g, S0.copy()) inverse_cholesky(C0) # result returned in lower triangle tri2full(S0_inv, 'L') S0_inv = inv(S0_inv) # tri2full(C0) # symmetrize assert glob.check(H0) and glob.check(S0) and glob.check(C0) # Create distributed destriptors with various block sizes: dist = grid.new_descriptor(N, N, 8, 8) # Distributed matrices: # We can use empty here, but end up with garbage on # on the other half of the triangle when we redistribute. # This is fine because ScaLAPACK does not care. H = dist.empty(dtype=dtype) S = dist.empty(dtype=dtype) Sinv = dist.empty(dtype=dtype) Z = dist.empty(dtype=dtype) C = dist.empty(dtype=dtype) Sinv = dist.empty(dtype=dtype) # Eigenvalues are non-BLACS matrices W = np.empty((N), dtype=float) W_dc = np.empty((N), dtype=float) W_mr3 = np.empty((N), dtype=float) W_g = np.empty((N), dtype=float) W_g_dc = np.empty((N), dtype=float) W_g_mr3 = np.empty((N), dtype=float) Glob2dist = Redistributor(world, glob, dist) Glob2dist.redistribute(H0, H, uplo='L') Glob2dist.redistribute(S0, S, uplo='L') Glob2dist.redistribute(S0, C, uplo='L') # C0 was previously overwritten Glob2dist.redistribute(S0, Sinv, uplo='L') # we don't test the expert drivers anymore since there # might be a buffer overflow error ## scalapack_diagonalize_ex(dist, H.copy(), Z, W, 'L') scalapack_diagonalize_dc(dist, H.copy(), Z, W_dc, 'L') ## scalapack_diagonalize_mr3(dist, H.copy(), Z, W_mr3, 'L') ## scalapack_general_diagonalize_ex(dist, H.copy(), S.copy(), Z, W_g, 'L') scalapack_general_diagonalize_dc(dist, H.copy(), S.copy(), Z, W_g_dc, 'L') ## scalapack_general_diagonalize_mr3(dist, H.copy(), S.copy(), Z, W_g_mr3, 'L') scalapack_inverse_cholesky(dist, C, 'L') if dtype == complex: # Only supported for complex for now scalapack_inverse(dist, Sinv, 'L') # Undo redistribute C_test = glob.empty(dtype=dtype) Sinv_test = glob.empty(dtype=dtype) Dist2glob = Redistributor(world, dist, glob) Dist2glob.redistribute(C, C_test) Dist2glob.redistribute(Sinv, Sinv_test) if rank == 0: ## diag_ex_err = abs(W - W0).max() diag_dc_err = abs(W_dc - W0).max() ## diag_mr3_err = abs(W_mr3 - W0).max() ## general_diag_ex_err = abs(W_g - W0_g).max() general_diag_dc_err = abs(W_g_dc - W0_g).max() ## general_diag_mr3_err = abs(W_g_mr3 - W0_g).max() inverse_chol_err = abs(C_test - C0).max() tri2full(Sinv_test, 'L') inverse_err = abs(Sinv_test - S0_inv).max() ## print 'diagonalize ex err', diag_ex_err print('diagonalize dc err', diag_dc_err) ## print 'diagonalize mr3 err', diag_mr3_err ## print 'general diagonalize ex err', general_diag_ex_err print('general diagonalize dc err', general_diag_dc_err) ## print 'general diagonalize mr3 err', general_diag_mr3_err print('inverse chol err', inverse_chol_err) if dtype == complex: print('inverse err', inverse_err) else: ## diag_ex_err = 0.0 diag_dc_err = 0.0 ## diag_mr3_err = 0.0 ## general_diag_ex_err = 0.0 general_diag_dc_err = 0.0 ## general_diag_mr3_err = 0.0 inverse_chol_err = 0.0 inverse_err = 0.0 # We don't like exceptions on only one cpu ## diag_ex_err = world.sum(diag_ex_err) diag_dc_err = world.sum(diag_dc_err) ## diag_mr3_err = world.sum(diag_mr3_err) ## general_diag_ex_err = world.sum(general_diag_ex_err) general_diag_dc_err = world.sum(general_diag_dc_err) ## general_diag_mr3_err = world.sum(general_diag_mr3_err) inverse_chol_err = world.sum(inverse_chol_err) inverse_err = world.sum(inverse_err) ## assert diag_ex_err < tol assert diag_dc_err < tol ## assert diag_mr3_err < tol ## assert general_diag_ex_err < tol assert general_diag_dc_err < tol ## assert general_diag_mr3_err < tol assert inverse_chol_err < tol if dtype == complex: assert inverse_err < tol
def _diagonalize(self, H_NN, eps_N): """Serial diagonalize via LAPACK.""" # This is replicated computation but ultimately avoids # additional communication. diagonalize(H_NN, eps_N)
def main(N=73, seed=42, mprocs=2, nprocs=2, dtype=float): gen = np.random.RandomState(seed) grid = BlacsGrid(world, mprocs, nprocs) if (dtype==complex): epsilon = 1.0j else: epsilon = 0.0 # Create descriptors for matrices on master: glob = grid.new_descriptor(N, N, N, N) # print globA.asarray() # Populate matrices local to master: H0 = glob.zeros(dtype=dtype) + gen.rand(*glob.shape) S0 = glob.zeros(dtype=dtype) + gen.rand(*glob.shape) C0 = glob.empty(dtype=dtype) if rank == 0: # Complex case must have real numbers on the diagonal. # We make a simple complex Hermitian matrix below. H0 = H0 + epsilon * (0.1*np.tri(N, N, k= -N // nprocs) + 0.3*np.tri(N, N, k=-1)) S0 = S0 + epsilon * (0.2*np.tri(N, N, k= -N // nprocs) + 0.4*np.tri(N, N, k=-1)) # Make matrices symmetric rk(1.0, H0.copy(), 0.0, H0) rk(1.0, S0.copy(), 0.0, S0) # Overlap matrix must be semi-positive definite S0 = S0 + 50.0*np.eye(N, N, 0) # Hamiltonian is usually diagonally dominant H0 = H0 + 75.0*np.eye(N, N, 0) C0 = S0.copy() # Local result matrices W0 = np.empty((N),dtype=float) W0_g = np.empty((N),dtype=float) # Calculate eigenvalues if rank == 0: diagonalize(H0.copy(), W0) general_diagonalize(H0.copy(), W0_g, S0.copy()) inverse_cholesky(C0) # result returned in lower triangle # tri2full(C0) # symmetrize assert glob.check(H0) and glob.check(S0) and glob.check(C0) # Create distributed destriptors with various block sizes: dist = grid.new_descriptor(N, N, 8, 8) # Distributed matrices: # We can use empty here, but end up with garbage on # on the other half of the triangle when we redistribute. # This is fine because ScaLAPACK does not care. H = dist.empty(dtype=dtype) S = dist.empty(dtype=dtype) Z = dist.empty(dtype=dtype) C = dist.empty(dtype=dtype) # Eigenvalues are non-BLACS matrices W = np.empty((N), dtype=float) W_dc = np.empty((N), dtype=float) W_mr3 = np.empty((N), dtype=float) W_g = np.empty((N), dtype=float) W_g_dc = np.empty((N), dtype=float) W_g_mr3 = np.empty((N), dtype=float) Glob2dist = Redistributor(world, glob, dist) Glob2dist.redistribute(H0, H, uplo='L') Glob2dist.redistribute(S0, S, uplo='L') Glob2dist.redistribute(S0, C, uplo='L') # C0 was previously overwritten # we don't test the expert drivers anymore since there # might be a buffer overflow error ## scalapack_diagonalize_ex(dist, H.copy(), Z, W, 'L') scalapack_diagonalize_dc(dist, H.copy(), Z, W_dc, 'L') ## scalapack_diagonalize_mr3(dist, H.copy(), Z, W_mr3, 'L') ## scalapack_general_diagonalize_ex(dist, H.copy(), S.copy(), Z, W_g, 'L') scalapack_general_diagonalize_dc(dist, H.copy(), S.copy(), Z, W_g_dc, 'L') ## scalapack_general_diagonalize_mr3(dist, H.copy(), S.copy(), Z, W_g_mr3, 'L') scalapack_inverse_cholesky(dist, C, 'L') # Undo redistribute C_test = glob.empty(dtype=dtype) Dist2glob = Redistributor(world, dist, glob) Dist2glob.redistribute(C, C_test) if rank == 0: ## diag_ex_err = abs(W - W0).max() diag_dc_err = abs(W_dc - W0).max() ## diag_mr3_err = abs(W_mr3 - W0).max() ## general_diag_ex_err = abs(W_g - W0_g).max() general_diag_dc_err = abs(W_g_dc - W0_g).max() ## general_diag_mr3_err = abs(W_g_mr3 - W0_g).max() inverse_chol_err = abs(C_test-C0).max() ## print 'diagonalize ex err', diag_ex_err print 'diagonalize dc err', diag_dc_err ## print 'diagonalize mr3 err', diag_mr3_err ## print 'general diagonalize ex err', general_diag_ex_err print 'general diagonalize dc err', general_diag_dc_err ## print 'general diagonalize mr3 err', general_diag_mr3_err print 'inverse chol err', inverse_chol_err else: ## diag_ex_err = 0.0 diag_dc_err = 0.0 ## diag_mr3_err = 0.0 ## general_diag_ex_err = 0.0 general_diag_dc_err = 0.0 ## general_diag_mr3_err = 0.0 inverse_chol_err = 0.0 # We don't like exceptions on only one cpu ## diag_ex_err = world.sum(diag_ex_err) diag_dc_err = world.sum(diag_dc_err) ## diag_mr3_err = world.sum(diag_mr3_err) ## general_diag_ex_err = world.sum(general_diag_ex_err) general_diag_dc_err = world.sum(general_diag_dc_err) ## general_diag_mr3_err = world.sum(general_diag_mr3_err) inverse_chol_err = world.sum(inverse_chol_err) ## assert diag_ex_err < tol assert diag_dc_err < tol ## assert diag_mr3_err < tol ## assert general_diag_ex_err < tol assert general_diag_dc_err < tol ## assert general_diag_mr3_err < tol assert inverse_chol_err < tol
from __future__ import print_function import numpy as np tol = 1e-8 a = np.eye(3, dtype=complex) a[1:, 0] = 0.01j w0 = [0.98585786, 1.0, 1.01414214] # NumPy's Diagonalize from numpy.linalg import eigh w = eigh(a)[0] print(w) assert abs(w - w0).max() < tol # LAPACK's QR Diagonalize from gpaw.utilities.lapack import diagonalize diagonalize(a.copy(), w) print(w) assert abs(w - w0).max() < tol # LAPACK's MR3 Diagonalize # Requires Netlib LAPACK 3.2.1 or later # from gpaw.utilities.lapack import diagonalize_mr3 # z = np.zeros_like(a) # diagonalize_mr3(a, w, z) # print w # assert abs(w - w0).max() < tol
if rank != 0: B = np.zeros((N, N)) world.broadcast(B, 0) return eps, B # generate a matrix N = 512 A = np.arange(N**2,dtype=float).reshape(N,N) for i in range(N): for j in range(i,N): A[i,j] = A[j,i] # diagonalize eps, B = scal_diagonalize(A) check = 1 if check and rank == 0: # check whether it gives the same result with lapack eps1 = np.zeros(N) diagonalize(A, eps1) assert np.abs(eps-eps1).sum() < 1e-6 for i in range(N//size): # the eigenvectors are row of the matrix, it can be differ by a minus sign. if np.abs(A[i,:] - B[i,:]).sum() > 1e-6: if np.abs(A[i,:] + B[i,:]).sum() > 1e-6: raise ValueError('Check !')
def orthonormalize(self, wfs, kpt, psit_nG=None): """Orthonormalizes the vectors a_nG with respect to the overlap. First, a Cholesky factorization C is done for the overlap matrix S_nn = <a_nG | S | a_nG> = C*_nn C_nn Cholesky matrix C is inverted and orthonormal vectors a_nG' are obtained as:: psit_nG' = inv(C_nn) psit_nG __ ~ _ \ -1 ~ _ psi (r) = ) C psi (r) n /__ nm m m Parameters ---------- psit_nG: ndarray, input/output On input the set of vectors to orthonormalize, on output the overlap-orthonormalized vectors. kpt: KPoint object: k-point object from kpoint.py. work_nG: ndarray Optional work array for overlap matrix times psit_nG. work_nn: ndarray Optional work array for overlap matrix. """ self.timer.start('Orthonormalize') if psit_nG is None: psit_nG = kpt.psit_nG P_ani = kpt.P_ani self.timer.start('projections') wfs.pt.integrate(psit_nG, P_ani, kpt.q) self.timer.stop('projections') # Construct the overlap matrix: operator = wfs.matrixoperator def S(psit_G): return psit_G def dS(a, P_ni): return np.dot(P_ni, wfs.setups[a].dO_ii) self.timer.start('calc_s_matrix') S_nn = operator.calculate_matrix_elements(psit_nG, P_ani, S, dS) self.timer.stop('calc_s_matrix') orthonormalization_string = repr(self.ksl) self.timer.start(orthonormalization_string) # if extra_parameters.get('sic', False): # # symmetric Loewdin Orthonormalization tri2full(S_nn, UL='L', map=np.conj) nrm_n = np.empty(S_nn.shape[0]) diagonalize(S_nn, nrm_n) nrm_nn = np.diag(1.0/np.sqrt(nrm_n)) S_nn = np.dot(np.dot(S_nn.T.conj(), nrm_nn), S_nn) else: # self.ksl.inverse_cholesky(S_nn) # S_nn now contains the inverse of the Cholesky factorization. # Let's call it something different: C_nn = S_nn del S_nn self.timer.stop(orthonormalization_string) self.timer.start('rotate_psi') operator.matrix_multiply(C_nn, psit_nG, P_ani, out_nG=kpt.psit_nG) self.timer.stop('rotate_psi') self.timer.stop('Orthonormalize')