Exemple #1
0
 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
Exemple #2
0
 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
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
0
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
Exemple #9
0
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
Exemple #10
0
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