Beispiel #1
0
def trid(mat_in, mode='givens'):
    """
    Tri-diagonalization of symmetrical real matrix\n
    # input requirement\n
    mat_in: symmetrical real matrix, use FLOAT data type, or will emerge huge roundoff error\n
    mode: 'givens' or 'householder', 'householder' works faster than 'givens' for 'givens'
    will seperately work on every off-tri-diagonal element in an iterative manner, not recommended
    for use other than diagonalization, although there are more efficient diagonalization method\n
    # output description\n
    [tridiag, U]\n
    tridiag: tri-diagonalized matrix\n
    U: unitary operator\n
    # formula\n
    mat_in = U·tridiag·U', where U' denotes transpose of U
    """

    if not mlib.symm_check(mat=mat_in):

        print('***error*** symmetric matrix is demanded.')
        exit()

    if mode == 'givens':

        [tridiag, U] = givens_tdiag(mat_in=mat_in, verbosity='silent')
    elif mode == 'householder':

        nline = len(mat_in)

        mat_op_on = deepcopy(mat_in)
        mat_op_on_T = mlib.transpose(mat_op_on)
        U = mlib.eye(nline)

        for iline in range(nline - 1):

            vec_op_on = mat_op_on_T[iline][iline + 1::]
            reflect_op = hh(vec_in=vec_op_on, verbosity='silent')
            identi_op = mlib.eye(iline + 1)
            op = mlib.combine_block(identi_op, reflect_op)

            #mat_op_on = mlib.dot(op, mat_op_on)
            mat_op_on = mlib.unitary_transform(op, mat_op_on)
            mat_op_on_T = mlib.transpose(mat_op_on)
            U = mlib.dot(op, U)

        U = mlib.transpose(U)
        tridiag = mat_op_on

    else:

        exit()

    return [tridiag, U]
Beispiel #2
0
def qr(mat_in, mode='householder', verbosity='silent'):
    """
    QR decomposition\n
    A = QR, where R is upper-triangonal matrix\n
    # input requirement\n
    mat_in: matrix to perform QR decomposition, only squared matrix is supported\n
    mode: 'householder' (recommended) or 'schmidt' (not recommended, bug exists, unsolved)\n
    # output description\n
    [original matrix, Q matrix, R matrix]
    """
    nline = len(mat_in)
    mat_op_on = deepcopy(mat_in)

    if mode == 'householder':

        mat_op_on_T = mlib.transpose(mat_op_on)
        op_log = []
        for iline in range(nline):

            vec_op_on = mat_op_on_T[iline][iline::]
            reflect_op = hh(vec_in=vec_op_on, verbosity=verbosity)
            identi_op = mlib.eye(iline)
            op = mlib.combine_block(identi_op, reflect_op)
            if verbosity == 'debug':
                print('QR| (householder) matrix before operation:\n{}'.format(
                    mat_op_on))
            mat_op_on = mlib.dot(op, mat_op_on)
            if verbosity == 'debug':
                print(
                    'QR| (householder) matrix after operation:\n{}\n OPERATION:\n{}'
                    .format(mat_op_on, op))
            mat_op_on_T = mlib.transpose(mat_op_on)
            op_log.append(op)

        Q = mlib.eye(nline)
        for iop in op_log:

            Q = mlib.dot(iop, Q)

        Q = mlib.transpose(Q)
        return [mat_in, Q, mat_op_on]

    elif mode == 'schmidt':

        #print('QR| ***warning*** There seems one bug that has not been discovered yet, although Gram-Schmidt works well.')
        [_, Q] = gs(mat_in, mode='column', verbosity=verbosity)

        Q_t = mlib.transpose(Q)
        R = mlib.dot(Q_t, mat_op_on)

        return [mat_in, Q, R]
Beispiel #3
0
def ql(mat_in, verbosity = 'silent'):

    # use householder by default
    mat_op_on = deepcopy(mat_in)
    
    nline = len(mat_op_on)
    Qt = mlib.eye(nline)

    for iline in range(nline):

        mat_op_on_T = mlib.transpose(mat_op_on)
        vec_in = mat_op_on_T[-iline-1][:(nline-iline)]
        norm_vec = mlib.mod_of_vec(vec_in)
        vec_desti = mlib.zeros(n = 1, m = nline-iline)[0][:]
        vec_desti[-1] = norm_vec

        reflect_op = hh(vec_in, vec_desti, mode = 'L', verbosity = verbosity)
        identi_op = mlib.eye(iline)
        op = mlib.combine_block(reflect_op, identi_op)

        if verbosity == 'debug':
            print('QL| vector read-in: {}\nQL| vector reflected to: {}\n'.format(vec_in, vec_desti))
            print('QL| Reflection operator:')
            mlib.matrix_print(reflect_op, decimal = 4)
            print('QL| Integrated Householder operator:')
            mlib.matrix_print(op, decimal = 4)
            print('QL| Present matrix before operation:')
            mlib.matrix_print(mat_op_on, decimal = 4)

        Qt = mlib.dot(op, Qt)

        mat_op_on = mlib.dot(op, mat_op_on)

        if verbosity == 'debug':
            print('Present matrix after operation:')
            mlib.matrix_print(mat_op_on, decimal = 4)

    Q = mlib.transpose(Qt)

    return [Q, mat_op_on]
Beispiel #4
0
def gs_orth(vec_set, mode = 'column', start = 0, normalize = True, verbosity = 'silent'):

    """
    Gram-Schmidt orthogonalization\n
    WARNING: input matrix (I mean vector set) must be float data type. An integar data type
    will cause unexpected large roundoff error, even totally wrong result will be returned!\n
    # input requirement\n
    vec_set: set of vectors that need to be orthogonalized, 2d array (list), FLOAT\n
    mode: 'column' or 'row', specify how vectors are placed in matrix the first parameter you
    entered\n
    start: which vector is selected as a reference to orthogonalize all other vectors, note 
    that this number corresponds to index of vector, so the first vector is '0' rather than '1
    '\n
    normalize: True or False, choose whether all vectors output are already normalized\n
    # output description\n
    [original vector set, resultant matrix containing orthogonalized vectors]

    """
    # Gram-Schmidt method
    len_vec = len(vec_set)
    nvec = len(vec_set[-1][:])
    if mode == 'row':
        temp = nvec
        nvec = len_vec
        len_vec = temp
    
    norm_orth_set = mlib.zeros(nvec, m = len_vec)
    orth_set = mlib.zeros(nvec, m = len_vec)

    # original vector collection, no matter how they arrange, <| or |>, save them as <|
    vec_colle = []
    vec_set_bak = deepcopy(vec_set)

    if mode == 'column':

        for icol in range(nvec):

            _vec = []
            _vec = [vec_set[i][icol] for i in range(len_vec)]
            vec_colle.append(_vec)
        if verbosity == 'debug':
            print('GRAM-SCHMIDT| |i> => <i|, column vectors have been saved as <| for easy calculation:\n{}'.format(vec_colle))
    elif mode == 'row':

        for irow in range(nvec):

            _vec = []
            _vec = [vec_set[irow][i] for i in range(len_vec)]
            vec_colle.append(_vec)
        if verbosity == 'debug':
            print('GRAM-SCHMIDT| row vectors have been saved:{}'.format(vec_colle))

    else:
        print('***error*** invalid mode required in reading input vectors set.')
        exit()
    

    # will save mod of every vector
    mod_vec = []
    for ivec in range(nvec):

        mod = mlib.mod_of_vec(vec = vec_colle[ivec][:])
        mod_vec.append(mod)
    
    # select no. start as the first basis and directly normalize it
    orth_set[start][:] = vec_colle[start][:]
    norm_orth_set[start][:] = [vec_colle[start][i]/mod_vec[start] for i in range(len_vec)]
    if verbosity == 'debug':
        print('GRAM-SCHMIDT| The first basis has been fixed as:\n{}\nGRAM-SCHMIDT| Normalized:\n{}'.format(orth_set[start][:], norm_orth_set[start][:]))
    orthlog = [start]

    for i in range(nvec):

        if i == start:
            continue

        vec2orth = vec_colle[i][:]
        cut = mlib.zeros(n = 1, m = len_vec)[0][:]

        for index in orthlog:
            
            innerprod = mlib.braket(vec2orth, norm_orth_set[index][:])
            compo2cut = [innerprod*item for item in norm_orth_set[index][:]]
            cut = mlib.plus(compo2cut, cut)
            if verbosity == 'debug':
                print('GRAM-SCHMIDT| Present vector to perform Gram-Schmidt:\n{}\nGRAM-SCHMIDT| Basis:\n{}'.format(vec2orth, norm_orth_set[index][:]))
                print('GRAM-SCHMIDT| scalar product between present vector and basis: {}'.format(innerprod))
                print('GRAM-SCHMIDT| vector needed to be subtract from original vector is:\n{}'.format(compo2cut))
        orth_set[i][:] = mlib.minus(vec2orth, cut)
        mod_vec[i] = mlib.mod_of_vec(orth_set[i][:]) #refresh mod info
        norm_orth_set[i][:] = [item/mod_vec[i] for item in orth_set[i][:]]
        if verbosity == 'debug':
            print('GRAM-SCHMIDT| Yield new unnormalized and normalized basis:\n{}\n{}'.format(orth_set[i][:], norm_orth_set[i][:]))
        orthlog.append(i)

    if mode == 'column':

        norm_orth_set = mlib.transpose(norm_orth_set)
        orth_set = mlib.transpose(orth_set)

    if normalize:

        return [vec_set_bak, norm_orth_set]
    else:

        return [vec_set_bak, orth_set]
Beispiel #5
0
def rayleigh_ritz_diag(mat_in,
                       num_eigen,
                       preconditioner='full',
                       diag_mode='householder',
                       dj_solver='lu',
                       sort_eigval='lowest',
                       batch_size=-1,
                       conv_thr=1E-6,
                       conv_calc_mode='norm1',
                       max_iter=50,
                       verbosity='silent'):
    """
    Subspace diagonalization (Rayleigh-Ritz subspace method)\n
    # input requirement\n
    mat_in: must be SQUARED matrix and in FLOAT data type\n
    num_eigen: number of eigen vectors and values want to find\n
    preconditioner: preconditioner of residual vector, avaliable options: 'full', 'single', 'dj' or 'none'.\n
    >For 'full' mode (recommended, most stable), (D_A - theta_i*I)|t_i> = |r_i>\n
    >, where DA is diagonal matrix that only has non-zero element on its diagonal, D_A[i][i] = A[i][i]\n
    >For 'single' mode (simple but always cannot converge), (A[i][i] - theta_i)|t_i> = |r_i>\n
    >For 'dj' (Davidson-Jacobi) mode (accurate but singluarity-unstable):\n
    > (I-|y_i><y_i|)(D_A - theta_i*I)(I-|y_i><y_i|)|t_i> = |r_i>\n
    > |t_i> will be solved by LU-decomposition and forward/back substitution method, relatively time-costly\n
    >For 'none' mode, preconditioner won't be used, i.e.: |t_i> = |r_i>\n
    diag_mode: 'jacobi', 'householder' or 'np' (numpy integrated). Basic algorithm for diagonalize matrix in subspace\n
    dj_solver: 'lu' or 'np', the most two fast algorithm for solving linear equation\n
    >For 'lu', use LU-decompsition and forward/backsubstitution\n
    >For 'np', use numpy.linalg.solve function\n
    batch_size: total number of dimensions of subspace, only will be read-in if mode is set to
    'batch'\n
    sort_eigval: 'lowest', 'highest' or 'None'\n
    >>For 'lowest', sort eigenvalues in an increasing order\n
    >>For 'highest', sort eigenvalues in an decreasing order\n
    >>For 'None', will not sort eigenvalues\n
    conv_thr: convergence threshold of eigen values for 'batch' mode, has no effect in other modes\n
    conv_calc_mode: 'abs', 'sqr', 'sum', 'norm1' or 'norm2', for measuring lists of eigenvalues of adjacent two iteration steps\n
    >>For 'abs', use absolute value of difference between element in old list and corresponding one in the new list\n
    >>For 'sqr', use squared value of ...\n
    >>For 'sum', just sum up all differences\n
    >>For 'norm1', use norm of difference between two lists that treated as vectors\n
    >>For 'norm2', only measure difference between norms of vectorized old and new list\n
    max_iter: maximum number of iterations for 'batch' mode, has no effect in other modes\n
    # output description\n
    [eigval_list, eigvec_list]\n
    eigval_list: list of eigenvalues\n
    eigvec_list: list of eigenvectors, arranged according to eigval_list\n
    """
    dim = len(mat_in)
    mat_op_on = deepcopy(mat_in)
    I = np.eye(dim)

    buffer_state = 'YES'
    if batch_size < num_eigen:

        batch_size = num_eigen
        buffer_state = 'NO'

    U = mlib.eye(n=dim, m=batch_size)

    eigval_list0 = mlib.zeros(n=1, m=num_eigen)[0][:]
    eigval_list = mlib.zeros(n=1, m=num_eigen)[0][:]

    eigval_conv = 1

    if (verbosity == 'high') or (verbosity == 'debug'):

        print('Diagonalization in subspace Initialization Information\n' +
              '-' * 50 + '\n' +
              'Preconditioner:                               {}\n'.format(
                  preconditioner) +
              'Number of eigenvalue-vector pairs to find:    {}\n'.format(
                  num_eigen) +
              'If buffer vectors used for batch mode:        {}\n'.format(
                  buffer_state))

    istep = 0
    while (istep < max_iter) and (eigval_conv > conv_thr):

        # --------------------subspace generation--------------------
        submat = mlib.unitary_transform(U=U, mat=mat_op_on)
        # -----------------------------------------------------------

        # -----------------subspace diagonalization------------------
        if diag_mode == 'np':

            [eigval_list, eigvec_set] = np.linalg.eig(submat)
        else:

            [eigval_list, eigvec_set] = hdiag(hmat_in=submat,
                                              mode=diag_mode,
                                              eigval_format='list',
                                              conv_level=8,
                                              max_iter=50,
                                              verbosity=verbosity)
        # -----------------------------------------------------------

        # ---------subspace eigenvalues and vectors sorting---------
        # sort eigenvalues
        if sort_eigval == 'None':
            # will not sort eigenvalues...
            pass
        elif (sort_eigval == 'lowest') or (sort_eigval == 'highest'):
            # sort eigenvalues anyway...
            sort_idx = np.argsort(a=eigval_list, axis=-1)
            # np.argsort will return a list of indices of elements in list to sort but
            # in a sorted order, ascendent as default
            if sort_eigval == 'highest':

                sort_idx = sort_idx[::-1]
                # reverse the indices list
        # -----------------------------------------------------------

        # --------------------eigenvalues storage--------------------
        templist = [eigval_list[idx] for idx in sort_idx]
        eigval_list = templist

        eigval_conv = mlib.list_diff(list_old=eigval_list0,
                                     list_new=eigval_list[0:num_eigen],
                                     mode=conv_calc_mode)
        eigval_list0 = eigval_list[0:num_eigen]
        # -----------------------------------------------------------

        # -----------------------preprocessing-----------------------
        # rearrange of eigenvectors in subspace
        for idim in range(batch_size):

            templist = [eigvec_set[idim][idx] for idx in sort_idx]
            eigvec_set[idim][:] = templist

        U_new = []
        for ivec in range(batch_size):

            s = eigvec_set[:][ivec]  # no. ivec subspace eigenvector,       bra
            y = mlib.dot(
                U, mlib.bra2ket(s),
                mode='matket')  # no. ivec original space Ritz vector, ket
            Resi_mat = mlib.minus(
                mat_op_on, mlib.eye(n=dim, m=dim, amplify=eigval_list[ivec]))
            r = mlib.dot(
                Resi_mat, y,
                mode='matket')  # no. ivec residual vector,            ket

            if preconditioner == 'full':

                t = []
                for icompo in range(len(r)):

                    ti = r[icompo][0] / (mat_op_on[icompo][icompo] -
                                         eigval_list[ivec])
                    t.append(ti)  # new vector to append to U,           bra
            elif preconditioner == 'single':

                orig_idx = sort_idx[ivec]
                t = [
                    -ri[0] /
                    (mat_op_on[orig_idx][orig_idx] - eigval_list[ivec])
                    for ri in r
                ]  #                         bra
            elif preconditioner == 'dj':
                r = [[-r[idim][0]] for idim in range(dim)]
                # (I-|y_i><y_i|)(D_A - theta_i*I)(I-|y_i><y_i|)|t_i> = |r_i>
                perp_op = mlib.minus(
                    I, mlib.ketbra(ket=y, bra=y, mode='2ket', amplify=1.0))
                # preconditioner of full mode
                full_prcdtnr = mlib.zeros(dim, dim)
                for idim in range(dim):
                    full_prcdtnr[idim][
                        idim] = mat_op_on[idim][idim] - eigval_list[ivec]
                # final assembly
                dj_op = mlib.unitary_transform(U=perp_op, mat=full_prcdtnr)
                # solve D|t> = |r>
                if dj_solver == 'lu':

                    if verbosity == 'high':
                        print(
                            'RAYLEIGH-RITZ| Start LU-decomposition...\nRAYLEIGH-RITZ| LU-decomposition carried out on matrix:'
                        )
                    [_, L_dj, U_dj] = lu(mat_in=dj_op)
                    if verbosity == 'high':
                        print('RAYLEIGH-RITZ| Start forwardsubstitution...')
                    y_dj = sbssolv(triang_mat=L_dj,
                                   b=mlib.ket2bra(r),
                                   mode='lower')
                    if verbosity == 'high':
                        print('RAYLEIGH-RITZ| Start backsubstitution...')
                    t = sbssolv(triang_mat=U_dj, b=y_dj, mode='upper'
                                )  # new vector to append to U,           bra
                elif dj_solver == 'np':

                    t = np.linalg.solve(dj_op, mlib.ket2bra(r))
                if verbosity == 'high':

                    print('RAYLEIGH-RITZ| New |t> generated!')
            elif preconditioner == 'none':

                t = mlib.ket2bra(r)
            else:

                print(
                    'RAYLEIGH-RITZ| ***WARNING***: preconditioner required is not recognized, use \'none\' instead.'
                )
                t = mlib.ket2bra(r)

            t = mlib.normalize(t)
            U_new.append(t)

        U_new = mlib.transpose(U_new)
        #[_, U, _] = qr(mat_in = U_new, mode = 'householder', verbosity = verbosity)
        #[U, _] = np.linalg.qr(U_new)
        [_, U] = gs(U_new)
        istep += 1
        if verbosity != 'silent':

            print('RAYLEIGH-RITZ| Step {}: conv = {}, conv_thr = {}'.format(
                istep, eigval_conv, conv_thr))

    return [eigval_list[0:num_eigen], U[:][0:num_eigen]]