Skip to content

haozhihan/module_diago

Repository files navigation

module_diago

module_diago is a minimal eigenvalue solver package using davidson subspace method with pybind11 and scikit-build-core.

Installation

  • Create and activate a new conda env
conda create -n diag_env python=3.8
conda activate diag_env
conda install numpy
conda install scipy
conda install pytest
  • Clone this repository
git clone https://github.com/haozhihan/module_diago.git
cd module_diago
git submodule update --init --recursive
  • Build pyabacus by pip install -v . or install test dependencies & build pyabacus by pip install .[test]. (Use pip install -v .[test] -i https://pypi.tuna.tsinghua.edu.cn/simple to accelerate installation process.)

Test

This project is tested by pytest. Run pytest -v in the tests directory to test the project.

cd tests
pytest -v

Usage

To use the package, you should first import the package by import module_diago.

Currently, module_diago implements a diagonalization algorithms in Python, namely hsolver.dav_subspace. The function signatures are as follows:

def dav_subspace(
    # Matrix-vector multiplication function, takes a numpy array and returns a numpy array
    mvv_op: Callable[[NDArray[np.complex128]], NDArray[np.complex128]],
    # Initial guess for the set of eigenvectors during diagonalization
    init_v: NDArray[np.complex128],
    # Matrix dimension
    dim: int,
    # Number of eigenvalues required, starting from the smallest eigenvalue, the algorithm will solve for num_eigs eigenvalues
    num_eigs: int,
    # Preconditioning vector
    pre_condition: NDArray[np.float64],
    # Number of vectors allowed in the basis set (dav_ndim * nband)
    dav_ndim: int = 2,
    # Iteration tolerance
    tol: float = 1e-2,
    # Maximum number of iterations
    max_iter: int = 1000,
    # Whether to use subspace function
    need_subspace: bool = False
) -> Tuple[NDArray[np.float64], NDArray[np.complex128]]:

dav_subspace returns a tuple consisting of an array of eigenvalues and the corresponding set of eigenvectors.

Before calling this function, we need to read a matrix first, which can be downloaded from https://sparse.tamu.edu/PARSEC. Then, we could use scipy to read it and determine the number of eigenvalues required (8 in this example):

import scipy

h_mat = scipy.io.loadmat(mat_file)['Problem']['A'][0, 0]
dim = h_mat.shape[0]
num_eigs = 8

We can also generate a diagonally dominant Hermitian matrix using numpy:

import numpy as np

n = 500
h_mat = np.random.rand(n, n)
h_mat = h_mat + h_mat.conj().T + np.diag(np.random.random(n)) * 10

Next, we can define the mvv_op operator:

def mvv_op(x):
    return h_mat.dot(x)
# Alternatively, you can define it as a lambda function
# mvv_op = lambda x: h_mat.dot(x)

Select the initial guess v0:

v0 = np.random.rand(nbasis, nband)

Compute the preconditioner precond. Since the matrix we read is a diagonally dominant sparse matrix, we can calculate the approximate inverse of the diagonal elements of h_mat as the preconditioner:

diag_elem = h_mat.diagonal()
# For numerical stability, to prevent some diagonal elements 
# from being too small (close to 0) and causing
# their reciprocals to be infinite, 
# we set points less than 1e-8 to 1e-8
diag_elem = np.where(np.abs(diag_elem) < 1e-8, 1e-8, diag_elem)
precond = 1.0 / np.abs(diag_elem)

After completing the above preparations, we can call the pyabacus algorithm to solve the eigenvalue problem!

e, v = dav_subspace(
    mvv_op,
    v0,
    nbasis,
    nband,
    precond,
    dav_ndim=8,
    tol=1e-8,
    max_iter=1000
)

print(f'eigenvalues calculated by pyabacus are: \n', e)

You can also refer to the examples directory for more examples.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors