Exemplo n.º 1
0
def householder(vec_in, vec_desti=[], mode='reduce', verbosity='silent'):
    """
    Householder algorithm\n
    Householder build a reflection operator that can transform one vector to one wanted
    direction\n
    # input requirement\n
    vec_in: one vector that want to reflect, SHOULD BE INPUT AS <|, 1d list\n
    vec_desti: one vector whose direction will vec_in be reflected onto, if not given
    explicitly, program will quit unless KEYWORD mode is set to 'reduce'\n
    mode: 'reduce' or anything else. 'reduce' mode means to reflect vec_in to direction
    along x-axis, i.e., [1, 0, 0, ...]\n
    # output description\n
    Householder operator P
    """
    len_vec = len(vec_in)
    mod_vec_in = mlib.mod_of_vec(vec_in)

    if mode == 'reduce':

        vec_desti = mlib.zeros(n=1, m=len_vec)[0][:]
        vec_desti[0] = mod_vec_in

    u = mlib.minus(vec_in, vec_desti)

    mod_u = mlib.mod_of_vec(u)
    v = mlib.zeros(n=1, m=len_vec)[0][:]
    for i in range(len(u)):

        if (u[i] == 0) and (mod_u == 0):
            v[i] = 1.0  # normalize manually
        else:
            v[i] = u[i] / mod_u
    # v = [iterm/mod_u for iterm in u]

    I = mlib.eye(len_vec)
    vvT = mlib.ketbra(v, v, mode='2bra', amplify=2)
    P = mlib.minus(I, vvT)
    if verbosity == 'debug':
        print('HOUSEHOLDER| Comprehensive report\n' + 'input check:\n' +
              'vector = {}\n'.format(vec_in) +
              'destination = {}\n'.format(vec_desti) +
              'norm vector (original) = {}\n'.format(u) +
              'normalized norm vector = {}'.format(v))
        print('2|v><v| tensor product  =')
        mlib.matrix_print(vvT)
        print('identity operator generated:\n{}\n'.format(I) +
              'Householder operator:\n{}'.format(P))
    return P
Exemplo n.º 2
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]
Exemplo n.º 3
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]
Exemplo n.º 4
0
def cholesky(mat_in, print_transpose=False, iexpr=False):
    """
    Cholesky decomposition\n
    # input requirement\n
    mat_in: input matrix, MUST BE: 1. POSITIVE DEFINITE, 2. SYMMETRY\n
    print_transpose: for Cholesky decomposition is to decompose positive-definite symmetry matrix into
    one lower-triangonal matrix and its transpose, i. e., A = LL', if set this flag to True, L' will 
    also be returned\n
    iexpr: if expressions of elements will be output by stdout\n
    # output description\n
    if print_transpose: [original matrix, L, L']\n
    if !print_transpose: [original matrix, L]
    """
    if mlib.det(mat_in=mat_in) == 0:

        print(
            '***error*** Singular matrix! Cholesky decomposition doesn\'t support present matrix!'
        )
        exit()

    mat_in_bak = deepcopy(mat_in)
    nline = len(mat_in)

    L = mlib.zeros(nline)
    U = mlib.zeros(nline)

    for i in range(nline):

        # diagonal element first to calculate
        expr_str_diag = 'L({}, {}) = sqrt[A({}, {})'.format(i, i, i, i)
        term_Aii = 0
        for j in range(i):

            term_Aii += L[i][j]**2
            word = ' - L({}, {})^2'.format(i, j)
            expr_str_diag += word

        if iexpr:
            print(expr_str_diag + ']')
        mat_in[i][i] -= term_Aii
        L[i][i] = sqrt(mat_in[i][i])
        U[i][i] = L[i][i]

        for j in range(i + 1, nline):

            expr_str_off_diag = 'L({}, {}) = [A({}, {})'.format(j, i, i, j)
            term_Aij = 0
            for k in range(i):

                word = ' - L({}, {})*L({}, {})'.format(k, i, k, j)
                expr_str_off_diag += word
                term_Aij += L[k][i] * L[k][j]

            if iexpr:
                print(expr_str_off_diag + ']/L({}, {})'.format(i, i))

            mat_in[i][j] -= term_Aij
            L[j][i] = mat_in[i][j] / L[i][i]
            U[i][j] = L[j][i]

    if print_transpose:

        return [mat_in_bak, L, U]
    else:

        return [mat_in_bak, L]
Exemplo n.º 5
0
def ludecomp(mat_in, pivot=False, iexpr=False):
    """
    Lower triangonal-Upper triangonal matrix decomposition, Crout Algorithm\n
    # input requirement\n
    mat_in: squared matrix\n
    pivot (not implemented): for actual use, there may be zero diagonal element that will cause numerical failure, 
    use pivot to swap rows of original matrix, therefore it is possible when zero diagonal element emerges, 
    program will return a result of LU decomposition of row-swapped original matrix, not that of original matrix. 
    If so, program will pop a warning on this unexpected condition\n
    iexpr: only available if mode == 'recursive', print expression of every element of lower and upper 
    triangonal matrices\n
    # output description\n
    [original matrix, Lower triangonal matrix, Upper triangonal matrix]
    """
    # in principle, should check if singular in advance.

    if mlib.det(mat_in=mat_in) == 0:

        print(
            '***error*** Singular matrix! LU decomposition doesn\'t support present matrix!'
        )
        exit()

    # deepcopy = save as
    mat_in_bak = deepcopy(mat_in)
    nline = len(mat_in)

    L = mlib.eye(nline)
    U = mlib.zeros(nline)

    if iexpr:
        print(
            '-' * 80 + '\n' +
            '>> Lower-Upper triangonal matrix decomposition (recursive mode): EXPRESSIONS <<\n'
            + '-' * 80)
    for i in range(nline):
        for j in range(i, nline):

            term_Aij = 0
            expr_str_U = 'U({}, {}) = A({}, {})'.format(i, j, i, j)
            for k in range(i):
                term_Aij += L[i][k] * U[k][j]
                word = ' - L({}, {})*U({}, {})'.format(i, k, k, j)
                expr_str_U += word
            mat_in[i][j] -= term_Aij
            U[i][j] = mat_in[i][j]
            if iexpr:
                print(expr_str_U)

        for j in range(i, nline):
            if j != i:

                term_Aji = 0
                expr_str_L_off_diag = 'L({}, {}) = [A({}, {})'.format(
                    j, i, j, i)
                for k in range(i):
                    term_Aji += L[j][k] * U[k][i]
                    word = ' - L({}, {})*U({}, {})'.format(j, k, k, i)
                    expr_str_L_off_diag += word
                mat_in[j][i] -= term_Aji
                L[j][i] = mat_in[j][i] / U[i][i]
                expr_str_L_off_diag = expr_str_L_off_diag + ']/U({}, {})'.format(
                    i, i)
                if iexpr:
                    print(expr_str_L_off_diag)
    if iexpr:
        print(
            'Numerical results can be collected by line: [A0, L, U] = ludecomp(A, mode = \'recursive\', iexpr = True)'
        )

    return [mat_in_bak, L, U]
Exemplo n.º 6
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]]