def qr(xs): #q, r = numpy.linalg.qr(numpy.asarray(xs).T) #q = [qi/numpy_helper.norm(qi) # for i, qi in enumerate(q.T) if r[i,i] > 1e-7] qs = [xs[0] / numpy_helper.norm(xs[0])] for i in range(1, len(xs)): xi = xs[i].copy() for j in range(len(qs)): xi -= qs[j] * numpy.dot(qs[j].conj(), xi) norm = numpy_helper.norm(xi) if norm > 1e-7: qs.append(xi / norm) return qs
def qr(xs): #q, r = numpy.linalg.qr(numpy.asarray(xs).T) #q = [qi/numpy_helper.norm(qi) # for i, qi in enumerate(q.T) if r[i,i] > 1e-7] qs = [xs[0]/numpy_helper.norm(xs[0])] for i in range(1, len(xs)): xi = xs[i].copy() for j in range(len(qs)): xi -= qs[j] * numpy.dot(qs[j], xi) norm = numpy_helper.norm(xi) if norm > 1e-7: qs.append(xi/norm) return qs
def dsolve(aop, b, precond, tol=1e-12, max_cycle=30, dot=numpy.dot, lindep=1e-16, verbose=0): '''Davidson iteration to solve linear equation. It works bad. ''' toloose = numpy.sqrt(tol) xs = [precond(b)] ax = [aop(xs[-1])] aeff = numpy.zeros((max_cycle,max_cycle), dtype=ax[0].dtype) beff = numpy.zeros((max_cycle), dtype=ax[0].dtype) for istep in range(max_cycle): beff[istep] = dot(xs[istep], b) for i in range(istep+1): aeff[istep,i] = dot(xs[istep], ax[i]) aeff[i,istep] = dot(xs[i], ax[istep]) v = scipy.linalg.solve(aeff[:istep+1,:istep+1], beff[:istep+1]) xtrial = dot(v, xs) dx = b - dot(v, ax) rr = numpy_helper.norm(dx) if verbose: print('davidson', istep, rr) if rr < toloose: break xs.append(precond(dx)) ax.append(aop(xs[-1])) if verbose: print(istep) return xtrial
def dsolve(aop, b, precond, tol=1e-14, max_cycle=30, dot=numpy.dot, lindep=1e-16, verbose=0): '''Davidson iteration to solve linear equation. It works bad. ''' toloose = numpy.sqrt(tol) xs = [precond(b)] ax = [aop(xs[-1])] aeff = numpy.zeros((max_cycle, max_cycle), dtype=ax[0].dtype) beff = numpy.zeros((max_cycle), dtype=ax[0].dtype) for istep in range(max_cycle): beff[istep] = dot(xs[istep], b) for i in range(istep + 1): aeff[istep, i] = dot(xs[istep], ax[i]) aeff[i, istep] = dot(xs[i], ax[istep]) v = scipy.linalg.solve(aeff[:istep + 1, :istep + 1], beff[:istep + 1]) xtrial = dot(v, xs) dx = b - dot(v, ax) rr = numpy_helper.norm(dx) if verbose: print('davidson', istep, rr) if rr < toloose: break xs.append(precond(dx)) ax.append(aop(xs[-1])) if verbose: print(istep) return xtrial
def davidson(aop, x0, precond, tol=1e-14, max_cycle=50, max_space=12, lindep=1e-14, max_memory=2000, dot=numpy.dot, callback=None, nroots=1, lessio=False, verbose=logger.WARN): '''Davidson diagonalization method to solve a c = e c. Ref [1] E.R. Davidson, J. Comput. Phys. 17 (1), 87-94 (1975). [2] http://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter11.pdf Args: aop : function(x) => array_like_x aop(x) to mimic the matrix vector multiplication :math:`\sum_{j}a_{ij}*x_j`. The argument is a 1D array. The returned value is a 1D array. x0 : 1D array Initial guess precond : function(dx, e, x0) => array_like_dx Preconditioner to generate new trial vector. The argument dx is a residual vector ``a*x0-e*x0``; e is the current eigenvalue; x0 is the current eigenvector. Kwargs: tol : float Convergence tolerance. max_cycle : int max number of iterations. max_space : int space size to hold trial vectors. lindep : float Linear dependency threshold. The function is terminated when the smallest eigenvalue of the metric of the trial vectors is lower than this threshold. max_memory : int or float Allowed memory in MB. dot : function(x, y) => scalar Inner product callback : function(envs_dict) => None callback function takes one dict as the argument which is generated by the builtin function :func:`locals`, so that the callback function can access all local variables in the current envrionment. nroots : int Number of eigenvalues to be computed. When nroots > 1, it affects the shape of the return value lessio : bool How to compute a*x0 for current eigenvector x0. There are two ways to compute a*x0. One is to assemble the existed a*x. The other is to call aop(x0). The default is the first method which needs more IO and less computational cost. When IO is slow, the second method can be considered. Returns: e : float or list of floats Eigenvalue. By default it's one float number. If :attr:`nroots` > 1, it is a list of floats for the lowest :attr:`nroots` eigenvalues. c : 1D array or list of 1D arrays Eigenvector. By default it's a 1D array. If :attr:`nroots` > 1, it is a list of arrays for the lowest :attr:`nroots` eigenvectors. Examples: >>> from pyscf import lib >>> a = numpy.random.random((10,10)) >>> a = a + a.T >>> aop = lambda x: numpy.dot(a,x) >>> precond = lambda dx, e, x0: dx/(a.diagonal()-e) >>> x0 = a[0] >>> e, c = lib.davidson(aop, x0, precond, nroots=2) >>> len(e) 2 ''' if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(sys.stdout, verbose) def qr(xs): #q, r = numpy.linalg.qr(numpy.asarray(xs).T) #q = [qi/numpy_helper.norm(qi) # for i, qi in enumerate(q.T) if r[i,i] > 1e-7] qs = [xs[0]/numpy_helper.norm(xs[0])] for i in range(1, len(xs)): xi = xs[i].copy() for j in range(len(qs)): xi -= qs[j] * numpy.dot(qs[j], xi) norm = numpy_helper.norm(xi) if norm > 1e-7: qs.append(xi/norm) return qs if isinstance(x0, numpy.ndarray) and x0.ndim == 1: xt = [x0] axt = [aop(x0)] max_cycle = min(max_cycle,x0.size) else: xt = qr(x0) axt = [aop(xi) for xi in xt] max_cycle = min(max_cycle,x0[0].size) max_space = max_space + nroots * 2 if max_memory*1e6/xt[0].nbytes/2 > max_space+nroots*2: xs = [] ax = [] _incore = True else: xs = _Xlist() ax = _Xlist() _incore = False toloose = numpy.sqrt(tol) * 1e-2 for i,xi in enumerate(xt): xs.append(xi) ax.append(axt[i]) space = len(xs) head = 0 heff = numpy.empty((max_space,max_space), dtype=x0[0].dtype) e = 0 for icyc in range(max_cycle): rnow = len(xt) for i in range(space): if head <= i < head+rnow: for k in range(i-head+1): heff[head+k,i] = dot(xt[k].conj(), axt[i-head]) heff[i,head+k] = heff[head+k,i].conj() else: for k in range(rnow): heff[head+k,i] = dot(xt[k].conj(), ax[i]) heff[i,head+k] = heff[head+k,i].conj() w, v = scipy.linalg.eigh(heff[:space,:space]) try: de = w[:nroots] - e except ValueError: de = w[:nroots] e = w[:nroots] x0 = [] ax0 = [] if lessio and not _incore: for k, ek in enumerate(e): x0.append(xs[space-1] * v[space-1,k]) for i in reversed(range(space-1)): xsi = xs[i] for k, ek in enumerate(e): x0[k] += v[i,k] * xsi ax0 = [aop(xi) for xi in x0] else: for k, ek in enumerate(e): x0 .append(xs[space-1] * v[space-1,k]) ax0.append(ax[space-1] * v[space-1,k]) for i in reversed(range(space-1)): xsi = xs[i] axi = ax[i] for k, ek in enumerate(e): x0 [k] += v[i,k] * xsi ax0[k] += v[i,k] * axi ide = numpy.argmax(abs(de)) if abs(de[ide]) < tol: log.debug('converge %d %d e= %s max|de|= %4.3g', icyc, space, e, de[ide]) break dx_norm = [] xt = [] for k, ek in enumerate(e): dxtmp = ax0[k] - ek * x0[k] xt.append(dxtmp) dx_norm.append(numpy_helper.norm(dxtmp)) if max(dx_norm) < toloose: log.debug('converge %d %d |r|= %4.3g e= %s max|de|= %4.3g', icyc, space, max(dx_norm), e, de[ide]) break # remove subspace linear dependency for k, ek in enumerate(e): if dx_norm[k] > toloose: xt[k] = precond(xt[k], e[0], x0[k]) xt[k] *= 1/numpy_helper.norm(xt[k]) else: xt[k] = None xt = [xi for xi in xt if xi is not None] for i in range(space): for xi in xt: xsi = xs[i] xi -= xsi * numpy.dot(xi, xsi) norm = 1 for i,xi in enumerate(xt): norm = numpy_helper.norm(xi) if norm > toloose: xt[i] *= 1/norm else: xt[i] = None xt = [xi for xi in xt if xi is not None] if len(xt) > 1: xt = qr(xt) if len(xt) == 0: log.debug('Linear dependency in trial subspace') break log.debug('davidson %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g', icyc, space, max(dx_norm), e, de[ide], norm) if space+len(xt) > max_space: if _incore: xs = [] ax = [] else: xs = _Xlist() ax = _Xlist() xt = x0 space = head = 0 e = 0 head = space axt = [] for k, xi in enumerate(xt): if head + k >= space: xs.append(xt[k]) axt.append(aop(xt[k])) ax.append(axt[k]) else: xs[head+k] = xt[k] axt.append(aop(xt[k])) ax[head+k] = axt[k] space += len(xt) if callable(callback): callback(locals()) if nroots == 1: return e[0], x0[0] else: return e, x0
def dgeev1(abop, x0, precond, type=1, tol=1e-12, max_cycle=50, max_space=12, lindep=1e-14, max_memory=2000, dot=numpy.dot, callback=None, nroots=1, lessio=False, verbose=logger.WARN): '''Davidson diagonalization method to solve A c = e B c. Args: abop : function([x]) => ([array_like_x], [array_like_x]) abop applies two matrix vector multiplications and returns tuple (Ax, Bx) x0 : 1D array Initial guess precond : function(dx, e, x0) => array_like_dx Preconditioner to generate new trial vector. The argument dx is a residual vector ``a*x0-e*x0``; e is the current eigenvalue; x0 is the current eigenvector. Kwargs: tol : float Convergence tolerance. max_cycle : int max number of iterations. max_space : int space size to hold trial vectors. lindep : float Linear dependency threshold. The function is terminated when the smallest eigenvalue of the metric of the trial vectors is lower than this threshold. max_memory : int or float Allowed memory in MB. dot : function(x, y) => scalar Inner product callback : function(envs_dict) => None callback function takes one dict as the argument which is generated by the builtin function :func:`locals`, so that the callback function can access all local variables in the current envrionment. nroots : int Number of eigenvalues to be computed. When nroots > 1, it affects the shape of the return value lessio : bool How to compute a*x0 for current eigenvector x0. There are two ways to compute a*x0. One is to assemble the existed a*x. The other is to call aop(x0). The default is the first method which needs more IO and less computational cost. When IO is slow, the second method can be considered. Returns: conv : bool Converged or not e : list of floats The lowest :attr:`nroots` eigenvalues. c : list of 1D arrays The lowest :attr:`nroots` eigenvectors. ''' if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(sys.stdout, verbose) toloose = numpy.sqrt(tol) * 1e-2 if isinstance(x0, numpy.ndarray) and x0.ndim == 1: x0 = [x0] #max_cycle = min(max_cycle, x0[0].size) max_space = max_space + nroots * 2 # max_space*3 for holding ax, bx and xs, nroots*3 for holding axt, bxt and xt _incore = max_memory*1e6/x0[0].nbytes > max_space*3+nroots*3 lessio = lessio and not _incore heff = numpy.empty((max_space,max_space), dtype=x0[0].dtype) seff = numpy.empty((max_space,max_space), dtype=x0[0].dtype) fresh_start = True conv = False for icyc in range(max_cycle): if fresh_start: if _incore: xs = [] ax = [] bx = [] else: xs = _Xlist() ax = _Xlist() bx = _Xlist() space = 0 # Orthogonalize xt space because the basis of subspace xs must be orthogonal # but the eigenvectors x0 are very likely non-orthogonal when A is non-Hermitian. xt, x0 = _qr(x0, dot), None e = numpy.zeros(nroots) fresh_start = False elif len(xt) > 1: xt = _qr(xt, dot) xt = xt[:40] # 40 trial vectors at most axt, bxt = abop(xt) if type > 1: axt = abop(bxt)[0] for k, xi in enumerate(xt): xs.append(xt[k]) ax.append(axt[k]) bx.append(bxt[k]) rnow = len(xt) head, space = space, space+rnow if type == 1: for i in range(space): if head <= i < head+rnow: for k in range(i-head+1): heff[head+k,i] = dot(xt[k].conj(), axt[i-head]) heff[i,head+k] = heff[head+k,i].conj() seff[head+k,i] = dot(xt[k].conj(), bxt[i-head]) seff[i,head+k] = seff[head+k,i].conj() else: for k in range(rnow): heff[head+k,i] = dot(xt[k].conj(), ax[i]) heff[i,head+k] = heff[head+k,i].conj() seff[head+k,i] = dot(xt[k].conj(), bx[i]) seff[i,head+k] = seff[head+k,i].conj() else: for i in range(space): if head <= i < head+rnow: for k in range(i-head+1): heff[head+k,i] = dot(bxt[k].conj(), axt[i-head]) heff[i,head+k] = heff[head+k,i].conj() seff[head+k,i] = dot(xt[k].conj(), bxt[i-head]) seff[i,head+k] = seff[head+k,i].conj() else: for k in range(rnow): heff[head+k,i] = dot(bxt[k].conj(), ax[i]) heff[i,head+k] = heff[head+k,i].conj() seff[head+k,i] = dot(xt[k].conj(), bx[i]) seff[i,head+k] = seff[head+k,i].conj() w, v = scipy.linalg.eigh(heff[:space,:space], seff[:space,:space]) if space < nroots or e.size != nroots: de = w[:nroots] else: de = w[:nroots] - e e = w[:nroots] x0 = _gen_x0(v[:,:nroots], xs) if lessio: ax0, bx0 = abop(x0) if type > 1: ax0 = abop(bx0)[0] else: ax0 = _gen_x0(v[:,:nroots], ax) bx0 = _gen_x0(v[:,:nroots], bx) ide = numpy.argmax(abs(de)) if abs(de[ide]) < tol: log.debug('converge %d %d e= %s max|de|= %4.3g', icyc, space, e, de[ide]) conv = True break dx_norm = [] xt = [] for k, ek in enumerate(e): if type == 1: dxtmp = ax0[k] - ek * bx0[k] else: dxtmp = ax0[k] - ek * x0[k] xt.append(dxtmp) dx_norm.append(numpy_helper.norm(dxtmp)) ax0 = bx0 = None if max(dx_norm) < toloose: log.debug('converge %d %d |r|= %4.3g e= %s max|de|= %4.3g', icyc, space, max(dx_norm), e, de[ide]) conv = True break # remove subspace linear dependency for k, ek in enumerate(e): if dx_norm[k] > toloose: xt[k] = precond(xt[k], e[0], x0[k]) xt[k] *= 1/numpy_helper.norm(xt[k]) else: xt[k] = None xt = [xi for xi in xt if xi is not None] for i in range(space): for xi in xt: xsi = xs[i] xi -= xsi * numpy.dot(xi, xsi) norm_min = 1 for i,xi in enumerate(xt): norm = numpy_helper.norm(xi) if norm > toloose: xt[i] *= 1/norm norm_min = min(norm_min, norm) else: xt[i] = None xt = [xi for xi in xt if xi is not None] log.debug('davidson %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g', icyc, space, max(dx_norm), e, de[ide], norm) if len(xt) == 0: log.debug('Linear dependency in trial subspace') break fresh_start = fresh_start or (space+len(xt) > max_space) if callable(callback): callback(locals()) if type == 3: for k in range(nroots): x0[k] = abop(x0[k])[1] return conv, e, x0
def eig(aop, x0, precond, tol=1e-14, max_cycle=50, max_space=12, lindep=1e-14, max_memory=2000, dot=numpy.dot, callback=None, nroots=1, lessio=False, left=False, pick=pickeig, verbose=logger.WARN): ''' A X = X w ''' assert(not left) if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(sys.stdout, verbose) def qr(xs): #q, r = numpy.linalg.qr(numpy.asarray(xs).T) #q = [qi/numpy_helper.norm(qi) # for i, qi in enumerate(q.T) if r[i,i] > 1e-7] qs = [xs[0]/numpy_helper.norm(xs[0])] for i in range(1, len(xs)): xi = xs[i].copy() for j in range(len(qs)): xi -= qs[j] * numpy.dot(qs[j], xi) norm = numpy_helper.norm(xi) if norm > 1e-7: qs.append(xi/norm) return qs toloose = numpy.sqrt(tol) * 1e-2 if isinstance(x0, numpy.ndarray) and x0.ndim == 1: x0 = [x0] max_cycle = min(max_cycle, x0[0].size) max_space = max_space + nroots * 2 # max_space*2 for holding ax and xs, nroots*2 for holding axt and xt _incore = max_memory*1e6/x0[0].nbytes > max_space*2+nroots*2 heff = numpy.empty((max_space,max_space), dtype=x0[0].dtype) fresh_start = True for icyc in range(max_cycle): if fresh_start: if _incore: xs = [] ax = [] else: xs = linalg_helper._Xlist() ax = linalg_helper._Xlist() space = 0 # Orthogonalize xt space because the basis of subspace xs must be orthogonal # but the eigenvectors x0 are very likely non-orthogonal when A is non-Hermitian. xt, x0 = qr(x0), None e = numpy.zeros(nroots) fresh_start = False elif len(xt) > 1: xt = qr(xt) xt = xt[:40] # 40 trial vectors at most axt = aop(xt) for k, xi in enumerate(xt): xs.append(xt[k]) ax.append(axt[k]) rnow = len(xt) head, space = space, space+rnow for i in range(rnow): for k in range(rnow): heff[head+k,head+i] = dot(xt[k].conj(), axt[i]) for i in range(head): axi = ax[i] xi = xs[i] for k in range(rnow): heff[head+k,i] = dot(xt[k].conj(), axi) heff[i,head+k] = dot(xi.conj(), axt[k]) w, v = scipy.linalg.eig(heff[:space,:space]) idx = pick(w, v, nroots) if idx.size < nroots or e.size != nroots: de = w[idx].real else: de = w[idx].real - e e = w[idx].real v = v[:,idx].real x0 = [] ax0 = [] if lessio and not _incore: for k, ek in enumerate(e): x0.append(xs[space-1] * v[space-1,k]) for i in reversed(range(space-1)): xsi = xs[i] for k, ek in enumerate(e): x0[k] += v[i,k] * xsi ax0 = aop(x0) else: for k, ek in enumerate(e): x0 .append(xs[space-1] * v[space-1,k]) ax0.append(ax[space-1] * v[space-1,k]) for i in reversed(range(space-1)): xsi = xs[i] axi = ax[i] for k, ek in enumerate(e): x0 [k] += v[i,k] * xsi ax0[k] += v[i,k] * axi ide = numpy.argmax(abs(de)) if abs(de[ide]) < tol: log.debug('converge %d %d e= %s max|de|= %4.3g', icyc, space, e, de[ide]) break dx_norm = [] xt = [] for k, ek in enumerate(e): dxtmp = ax0[k] - ek * x0[k] xt.append(dxtmp) dx_norm.append(numpy_helper.norm(dxtmp)) if max(dx_norm) < toloose: log.debug('converge %d %d |r|= %4.3g e= %s max|de|= %4.3g', icyc, space, max(dx_norm), e, de[ide]) break # remove subspace linear dependency for k, ek in enumerate(e): if dx_norm[k] > toloose: xt[k] = precond(xt[k], e[0], x0[k]) xt[k] *= 1/numpy_helper.norm(xt[k]) else: xt[k] = None xt = [xi for xi in xt if xi is not None] for i in range(space): xsi = xs[i] for xi in xt: xi -= xsi * numpy.dot(xi, xsi) norm_min = 1 for i,xi in enumerate(xt): norm = numpy_helper.norm(xi) if norm > toloose: xt[i] *= 1/norm norm_min = min(norm_min, norm) else: xt[i] = None xt = [xi for xi in xt if xi is not None] if len(xt) == 0: log.debug('Linear dependency in trial subspace') break log.debug('davidson %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g', icyc, space, max(dx_norm), e, de[ide], norm_min) fresh_start = fresh_start or (space+len(xt) > max_space) if callable(callback): callback(locals()) if nroots == 1: return e[0], x0[0] else: return e, x0
def davidson1(aop, x0, precond, tol=1e-14, max_cycle=50, max_space=12, lindep=1e-14, max_memory=2000, dot=numpy.dot, callback=None, nroots=1, lessio=False, verbose=logger.WARN): '''Davidson diagonalization method to solve a c = e c. Ref [1] E.R. Davidson, J. Comput. Phys. 17 (1), 87-94 (1975). [2] http://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter11.pdf Args: aop : function([x]) => [array_like_x] Matrix vector multiplication :math:`y_{ki} = \sum_{j}a_{ij}*x_{jk}`. x0 : 1D array or a list of 1D array Initial guess precond : function(dx, e, x0) => array_like_dx Preconditioner to generate new trial vector. The argument dx is a residual vector ``a*x0-e*x0``; e is the current eigenvalue; x0 is the current eigenvector. Kwargs: tol : float Convergence tolerance. max_cycle : int max number of iterations. max_space : int space size to hold trial vectors. lindep : float Linear dependency threshold. The function is terminated when the smallest eigenvalue of the metric of the trial vectors is lower than this threshold. max_memory : int or float Allowed memory in MB. dot : function(x, y) => scalar Inner product callback : function(envs_dict) => None callback function takes one dict as the argument which is generated by the builtin function :func:`locals`, so that the callback function can access all local variables in the current envrionment. nroots : int Number of eigenvalues to be computed. When nroots > 1, it affects the shape of the return value lessio : bool How to compute a*x0 for current eigenvector x0. There are two ways to compute a*x0. One is to assemble the existed a*x. The other is to call aop(x0). The default is the first method which needs more IO and less computational cost. When IO is slow, the second method can be considered. Returns: e : list of floats The lowest :attr:`nroots` eigenvalues. c : list of 1D arrays The lowest :attr:`nroots` eigenvectors. Examples: >>> from pyscf import lib >>> a = numpy.random.random((10,10)) >>> a = a + a.T >>> aop = lambda xs: [numpy.dot(a,x) for x in xs] >>> precond = lambda dx, e, x0: dx/(a.diagonal()-e) >>> x0 = a[0] >>> e, c = lib.davidson(aop, x0, precond, nroots=2) >>> len(e) 2 ''' if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(sys.stdout, verbose) def qr(xs): #q, r = numpy.linalg.qr(numpy.asarray(xs).T) #q = [qi/numpy_helper.norm(qi) # for i, qi in enumerate(q.T) if r[i,i] > 1e-7] qs = [xs[0] / numpy_helper.norm(xs[0])] for i in range(1, len(xs)): xi = xs[i].copy() for j in range(len(qs)): xi -= qs[j] * numpy.dot(qs[j].conj(), xi) norm = numpy_helper.norm(xi) if norm > 1e-7: qs.append(xi / norm) return qs toloose = numpy.sqrt(tol) * 1e-2 if isinstance(x0, numpy.ndarray) and x0.ndim == 1: x0 = [x0] max_cycle = min(max_cycle, x0[0].size) max_space = max_space + nroots * 2 # max_space*2 for holding ax and xs, nroots*2 for holding axt and xt _incore = max_memory * 1e6 / x0[0].nbytes > max_space * 2 + nroots * 2 heff = None fresh_start = True for icyc in range(max_cycle): if fresh_start: if _incore: xs = [] ax = [] else: xs = _Xlist() ax = _Xlist() space = 0 # Orthogonalize xt space because the basis of subspace xs must be orthogonal # but the eigenvectors x0 might not be strictly orthogonal xt, x0 = qr(x0), None e = numpy.zeros(nroots) fresh_start = False elif len(xt) > 1: xt = qr(xt) xt = xt[:40] # 40 trial vectors at most axt = aop(xt) for k, xi in enumerate(xt): xs.append(xt[k]) ax.append(axt[k]) rnow = len(xt) head, space = space, space + len(xt) if heff is None: # Lazy initilize heff to determine the dtype heff = numpy.empty((max_space + nroots, max_space + nroots), dtype=ax[0].dtype) for i in range(space): if head <= i < head + rnow: for k in range(i - head + 1): heff[head + k, i] = dot(xt[k].conj(), axt[i - head]) heff[i, head + k] = heff[head + k, i].conj() else: axi = ax[i] for k in range(rnow): heff[head + k, i] = dot(xt[k].conj(), axi) heff[i, head + k] = heff[head + k, i].conj() w, v = scipy.linalg.eigh(heff[:space, :space]) if space < nroots or e.size != nroots: de = w[:nroots] else: de = w[:nroots] - e e = w[:nroots] x0 = [] ax0 = [] if lessio and not _incore: for k, ek in enumerate(e): x0.append(xs[space - 1] * v[space - 1, k]) for i in reversed(range(space - 1)): xsi = xs[i] for k, ek in enumerate(e): x0[k] += v[i, k] * xsi ax0 = aop(x0) else: for k, ek in enumerate(e): x0.append(xs[space - 1] * v[space - 1, k]) ax0.append(ax[space - 1] * v[space - 1, k]) for i in reversed(range(space - 1)): xsi = xs[i] axi = ax[i] for k, ek in enumerate(e): x0[k] += v[i, k] * xsi ax0[k] += v[i, k] * axi ide = numpy.argmax(abs(de)) if abs(de[ide]) < tol: log.debug('converge %d %d e= %s max|de|= %4.3g', icyc, space, e, de[ide]) break dx_norm = [] xt = [] for k, ek in enumerate(e): dxtmp = ax0[k] - ek * x0[k] xt.append(dxtmp) dx_norm.append(numpy_helper.norm(dxtmp)) if max(dx_norm) < toloose: log.debug('converge %d %d |r|= %4.3g e= %s max|de|= %4.3g', icyc, space, max(dx_norm), e, de[ide]) break # remove subspace linear dependency for k, ek in enumerate(e): if dx_norm[k] > toloose: xt[k] = precond(xt[k], e[0], x0[k]) xt[k] *= 1 / numpy_helper.norm(xt[k]) else: xt[k] = None xt = [xi for xi in xt if xi is not None] for i in range(space): for xi in xt: xsi = xs[i] xi -= xsi * numpy.dot(xsi.conj(), xi) norm_min = 1 for i, xi in enumerate(xt): norm = numpy_helper.norm(xi) if norm > toloose: xt[i] *= 1 / norm norm_min = min(norm_min, norm) else: xt[i] = None xt = [xi for xi in xt if xi is not None] if len(xt) == 0: log.debug('Linear dependency in trial subspace') break log.debug( 'davidson %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g', icyc, space, max(dx_norm), e, de[ide], norm_min) fresh_start = (icyc + nroots < max_cycle and (fresh_start or space + nroots > max_space)) if callable(callback): callback(locals()) return e, x0
def eig(aop, x0, precond, tol=1e-14, max_cycle=50, max_space=12, lindep=1e-14, max_memory=2000, dot=numpy.dot, callback=None, nroots=1, lessio=False, left=False, pick=pickeig, verbose=logger.WARN): ''' A X = X w ''' assert (not left) if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(sys.stdout, verbose) def qr(xs): #q, r = numpy.linalg.qr(numpy.asarray(xs).T) #q = [qi/numpy_helper.norm(qi) # for i, qi in enumerate(q.T) if r[i,i] > 1e-7] qs = [xs[0] / numpy_helper.norm(xs[0])] for i in range(1, len(xs)): xi = xs[i].copy() for j in range(len(qs)): xi -= qs[j] * numpy.dot(qs[j], xi) norm = numpy_helper.norm(xi) if norm > 1e-7: qs.append(xi / norm) return qs toloose = numpy.sqrt(tol) * 1e-2 if isinstance(x0, numpy.ndarray) and x0.ndim == 1: x0 = [x0] max_cycle = min(max_cycle, x0[0].size) max_space = max_space + nroots * 2 # max_space*2 for holding ax and xs, nroots*2 for holding axt and xt _incore = max_memory * 1e6 / x0[0].nbytes > max_space * 2 + nroots * 2 heff = numpy.empty((max_space, max_space), dtype=x0[0].dtype) fresh_start = True for icyc in range(max_cycle): if fresh_start: if _incore: xs = [] ax = [] else: xs = linalg_helper._Xlist() ax = linalg_helper._Xlist() space = 0 # Orthogonalize xt space because the basis of subspace xs must be orthogonal # but the eigenvectors x0 are very likely non-orthogonal when A is non-Hermitian. xt, x0 = qr(x0), None e = numpy.zeros(nroots) fresh_start = False elif len(xt) > 1: xt = qr(xt) xt = xt[:40] # 40 trial vectors at most axt = aop(xt) for k, xi in enumerate(xt): xs.append(xt[k]) ax.append(axt[k]) rnow = len(xt) head, space = space, space + rnow for i in range(rnow): for k in range(rnow): heff[head + k, head + i] = dot(xt[k].conj(), axt[i]) for i in range(head): axi = ax[i] xi = xs[i] for k in range(rnow): heff[head + k, i] = dot(xt[k].conj(), axi) heff[i, head + k] = dot(xi.conj(), axt[k]) w, v = scipy.linalg.eig(heff[:space, :space]) idx = pick(w, v, nroots) if idx.size < nroots or e.size != nroots: de = w[idx].real else: de = w[idx].real - e e = w[idx].real v = v[:, idx].real x0 = [] ax0 = [] if lessio and not _incore: for k, ek in enumerate(e): x0.append(xs[space - 1] * v[space - 1, k]) for i in reversed(range(space - 1)): xsi = xs[i] for k, ek in enumerate(e): x0[k] += v[i, k] * xsi ax0 = aop(x0) else: for k, ek in enumerate(e): x0.append(xs[space - 1] * v[space - 1, k]) ax0.append(ax[space - 1] * v[space - 1, k]) for i in reversed(range(space - 1)): xsi = xs[i] axi = ax[i] for k, ek in enumerate(e): x0[k] += v[i, k] * xsi ax0[k] += v[i, k] * axi ide = numpy.argmax(abs(de)) if abs(de[ide]) < tol: log.debug('converge %d %d e= %s max|de|= %4.3g', icyc, space, e, de[ide]) break dx_norm = [] xt = [] for k, ek in enumerate(e): dxtmp = ax0[k] - ek * x0[k] xt.append(dxtmp) dx_norm.append(numpy_helper.norm(dxtmp)) if max(dx_norm) < toloose: log.debug('converge %d %d |r|= %4.3g e= %s max|de|= %4.3g', icyc, space, max(dx_norm), e, de[ide]) break # remove subspace linear dependency for k, ek in enumerate(e): if dx_norm[k] > toloose: xt[k] = precond(xt[k], e[0], x0[k]) xt[k] *= 1 / numpy_helper.norm(xt[k]) else: xt[k] = None xt = [xi for xi in xt if xi is not None] for i in range(space): xsi = xs[i] for xi in xt: xi -= xsi * numpy.dot(xi, xsi) norm_min = 1 for i, xi in enumerate(xt): norm = numpy_helper.norm(xi) if norm > toloose: xt[i] *= 1 / norm norm_min = min(norm_min, norm) else: xt[i] = None xt = [xi for xi in xt if xi is not None] if len(xt) == 0: log.debug('Linear dependency in trial subspace') break log.debug( 'davidson %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g', icyc, space, max(dx_norm), e, de[ide], norm_min) fresh_start = fresh_start or (space + len(xt) > max_space) if callable(callback): callback(locals()) if nroots == 1: return e[0], x0[0] else: return e, x0
def dgeev(abop, x0, precond, type=1, tol=1e-14, max_cycle=50, max_space=12, lindep=1e-14, max_memory=2000, dot=numpy.dot, callback=None, nroots=1, lessio=False, verbose=logger.WARN): '''Davidson diagonalization method to solve A c = e B c. Args: abop : function([x]) => ([array_like_x], [array_like_x]) abop applies two matrix vector multiplications and returns tuple (Ax, Bx) x0 : 1D array Initial guess precond : function(dx, e, x0) => array_like_dx Preconditioner to generate new trial vector. The argument dx is a residual vector ``a*x0-e*x0``; e is the current eigenvalue; x0 is the current eigenvector. Kwargs: tol : float Convergence tolerance. max_cycle : int max number of iterations. max_space : int space size to hold trial vectors. lindep : float Linear dependency threshold. The function is terminated when the smallest eigenvalue of the metric of the trial vectors is lower than this threshold. max_memory : int or float Allowed memory in MB. dot : function(x, y) => scalar Inner product callback : function(envs_dict) => None callback function takes one dict as the argument which is generated by the builtin function :func:`locals`, so that the callback function can access all local variables in the current envrionment. nroots : int Number of eigenvalues to be computed. When nroots > 1, it affects the shape of the return value lessio : bool How to compute a*x0 for current eigenvector x0. There are two ways to compute a*x0. One is to assemble the existed a*x. The other is to call aop(x0). The default is the first method which needs more IO and less computational cost. When IO is slow, the second method can be considered. Returns: e : list of floats The lowest :attr:`nroots` eigenvalues. c : list of 1D arrays The lowest :attr:`nroots` eigenvectors. ''' if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(sys.stdout, verbose) def qr(xs): #q, r = numpy.linalg.qr(numpy.asarray(xs).T) #q = [qi/numpy_helper.norm(qi) # for i, qi in enumerate(q.T) if r[i,i] > 1e-7] qs = [xs[0] / numpy_helper.norm(xs[0])] for i in range(1, len(xs)): xi = xs[i].copy() for j in range(len(qs)): xi -= qs[j] * numpy.dot(qs[j], xi) norm = numpy_helper.norm(xi) if norm > 1e-7: qs.append(xi / norm) return qs toloose = numpy.sqrt(tol) * 1e-2 if isinstance(x0, numpy.ndarray) and x0.ndim == 1: x0 = [x0] max_cycle = min(max_cycle, x0[0].size) max_space = max_space + nroots * 2 # max_space*3 for holding ax, bx and xs, nroots*3 for holding axt, bxt and xt _incore = max_memory * 1e6 / x0[0].nbytes > max_space * 3 + nroots * 3 heff = numpy.empty((max_space, max_space), dtype=x0[0].dtype) seff = numpy.empty((max_space, max_space), dtype=x0[0].dtype) fresh_start = True for icyc in range(max_cycle): if fresh_start: if _incore: xs = [] ax = [] bx = [] else: xs = linalg_helper._Xlist() ax = linalg_helper._Xlist() bx = linalg_helper._Xlist() space = 0 # Orthogonalize xt space because the basis of subspace xs must be orthogonal # but the eigenvectors x0 are very likely non-orthogonal when A is non-Hermitian. xt, x0 = qr(x0), None e = numpy.zeros(nroots) fresh_start = False elif len(xt) > 1: xt = qr(xt) xt = xt[:40] # 40 trial vectors at most axt, bxt = abop(xt) if type > 1: axt = abop(bxt)[0] for k, xi in enumerate(xt): xs.append(xt[k]) ax.append(axt[k]) bx.append(bxt[k]) rnow = len(xt) head, space = space, space + rnow if type == 1: for i in range(space): if head <= i < head + rnow: for k in range(i - head + 1): heff[head + k, i] = dot(xt[k].conj(), axt[i - head]) heff[i, head + k] = heff[head + k, i].conj() seff[head + k, i] = dot(xt[k].conj(), bxt[i - head]) seff[i, head + k] = seff[head + k, i].conj() else: for k in range(rnow): heff[head + k, i] = dot(xt[k].conj(), ax[i]) heff[i, head + k] = heff[head + k, i].conj() seff[head + k, i] = dot(xt[k].conj(), bx[i]) seff[i, head + k] = seff[head + k, i].conj() else: for i in range(space): if head <= i < head + rnow: for k in range(i - head + 1): heff[head + k, i] = dot(bxt[k].conj(), axt[i - head]) heff[i, head + k] = heff[head + k, i].conj() seff[head + k, i] = dot(xt[k].conj(), bxt[i - head]) seff[i, head + k] = seff[head + k, i].conj() else: for k in range(rnow): heff[head + k, i] = dot(bxt[k].conj(), ax[i]) heff[i, head + k] = heff[head + k, i].conj() seff[head + k, i] = dot(xt[k].conj(), bx[i]) seff[i, head + k] = seff[head + k, i].conj() w, v = scipy.linalg.eigh(heff[:space, :space], seff[:space, :space]) if space < nroots or e.size != nroots: de = w[:nroots] else: de = w[:nroots] - e e = w[:nroots] x0 = [] ax0 = [] bx0 = [] if lessio and not _incore: for k, ek in enumerate(e): x0.append(xs[space - 1] * v[space - 1, k]) for i in reversed(range(space - 1)): xsi = xs[i] for k, ek in enumerate(e): x0[k] += v[i, k] * xsi ax0, bx0 = abop(x0) if type > 1: ax0 = abop(bx0)[0] else: for k, ek in enumerate(e): x0.append(xs[space - 1] * v[space - 1, k]) ax0.append(ax[space - 1] * v[space - 1, k]) bx0.append(bx[space - 1] * v[space - 1, k]) for i in reversed(range(space - 1)): xsi = xs[i] axi = ax[i] bxi = bx[i] for k, ek in enumerate(e): x0[k] += v[i, k] * xsi ax0[k] += v[i, k] * axi bx0[k] += v[i, k] * bxi ide = numpy.argmax(abs(de)) if abs(de[ide]) < tol: log.debug('converge %d %d e= %s max|de|= %4.3g', icyc, space, e, de[ide]) break dx_norm = [] xt = [] for k, ek in enumerate(e): if type == 1: dxtmp = ax0[k] - ek * bx0[k] else: dxtmp = ax0[k] - ek * x0[k] xt.append(dxtmp) dx_norm.append(numpy_helper.norm(dxtmp)) if max(dx_norm) < toloose: log.debug('converge %d %d |r|= %4.3g e= %s max|de|= %4.3g', icyc, space, max(dx_norm), e, de[ide]) break # remove subspace linear dependency for k, ek in enumerate(e): if dx_norm[k] > toloose: xt[k] = precond(xt[k], e[0], x0[k]) xt[k] *= 1 / numpy_helper.norm(xt[k]) else: xt[k] = None xt = [xi for xi in xt if xi is not None] for i in range(space): for xi in xt: xsi = xs[i] xi -= xsi * numpy.dot(xi, xsi) norm_min = 1 for i, xi in enumerate(xt): norm = numpy_helper.norm(xi) if norm > toloose: xt[i] *= 1 / norm norm_min = min(norm_min, norm) else: xt[i] = None xt = [xi for xi in xt if xi is not None] if len(xt) == 0: log.debug('Linear dependency in trial subspace') break log.debug( 'davidson %d %d |r|= %4.3g e= %s max|de|= %4.3g lindep= %4.3g', icyc, space, max(dx_norm), e, de[ide], norm) fresh_start = fresh_start or (space + len(xt) > max_space) if callable(callback): callback(locals()) if type == 3: for k in range(nroots): x0[k] = abop(x0[k])[1] if nroots == 1: return e[0], x0[0] else: return e, x0