Skip to content

Commit 77b750b

Browse files
committed
Minimal changes
1 parent ac66e40 commit 77b750b

5 files changed

Lines changed: 27 additions & 15 deletions

File tree

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This is done following an efficient strategy specialized for symmetric matrices,
1212
The implementation of the solver is done using `mpi4py`. Moreover, the package relies on a `C++` backend that is automatically compiled when running `python -m pip install .`.
1313
A more detailed discussion on dependencies and on how to install the package is provided at the end of the `README.md` file.
1414
## Repo structure
15-
We implemented various GitHub workflows, which include unit testing, documentation generation and code formatting.
15+
We implemented various `GitHub` workflows, which include unit testing, documentation generation and code formatting.
1616

1717
1. Unit tests are performed using `pytest`. They are run automatically after each push. There are three test files in the `test` folder, namely `test_eigensolvers.py` (using to test the implementation of the Lanczos method and the QR algorithm), `test_zero_finder.py` (used to ensure correctness of helper functions for the divide et impera algorithm), and `test_utils.py` (to test that some helper functions work as expected).
1818
2. All the code is commented in detail in terms of docstrings and comments corresponding to the most salient lines of code. The documentation is generated automatially using `sphinx` at each push and deployed to `GitHub` pages.
@@ -31,12 +31,17 @@ In order to solve an eigenvalue problem, we considered multiple strategies.
3131
1. The most trivial one was to implement the power method in order to be able to compute (at least) the biggest eigenvalue. We then used `numba` to try and optimize it, but in this case just-in-time compilation was not extremely beneficial.The implementation of the power method is contained in `eigenvalues.py`.
3232
2. Lanczos + QR: this is an approach (tailored to the case of symmetric matrices) to compute *all* the eigenvalues and eigenvectors. Notice that, also in the case of the QR method,`numba` was not very beneficial in terms of speed-up, resulting in a pretty slow methodology. For this reason, we implemented the QR method in `C++` and used `pybind11` to expose it to `Python`. All the code written in `C++` can be found in `cxx_utils.cpp`.
3333
3. `CuPy` implementation of all of the above: we implemented all the above methodologies using `CuPy` to see whether using GPU could speed up computations. Since this was not the case, we commented all the lines of code involving `CuPy`, so that installation of the package is no longer required and we can use our code also on machines that do not have GPU.
34-
4. The core of the project is the implementation (as well as a generalization of the simplified case in which $\rho=1$ considered in our reference) of the _divide et implera_ method for the computation of eigenvalues of a symmetric matrix. Some helpers were originally written in `Python` and then translated to `C++` for efficiency reasons: their original implementation is in `zero_finder.py` and is still present in the project for testing purposes. The translated version can be found in `cxx_utils.cpp`. Instead, the implementation of the actual method to compute the eigenvalues starting from a tridiagonal matrix is contained in `parallel_tridiag_eigen.py` and makes use of `mpi4py`. Notice that the implementation of deflation in `cxx_utils.cpp` is done using the `Eigen` library.
34+
4. The core of the project is the implementation (as well as a generalization of the simplified case in which $\rho=1$ considered in our reference) of the _divide et impera_ method for the computation of eigenvalues of a symmetric matrix. Some helpers were originally written in `Python` and then translated to `C++` for efficiency reasons: their original implementation is in `zero_finder.py` and is still present in the project for testing purposes. The translated version can be found in `cxx_utils.cpp`. Instead, the implementation of the actual method to compute the eigenvalues starting from a tridiagonal matrix is contained in `parallel_tridiag_eigen.py` and makes use of `mpi4py`. Notice that the implementation of deflation in `cxx_utils.cpp` is done using the `Eigen` library.
3535

3636
# Results
3737
The results of the profiling (runtime vs matrix size, memory consumption, scalability, and so on) are discussed in detail in `Documentation.ipynb`.
3838
All the scripts in the `scripts` folder are either used for profiling or to provide running examples.
3939

40+
## Important remark
41+
The method that we implemented was tested thoroughly at all stages of development using `pytest`.
42+
Nevertheless, the algorithm that we chose seems to lack robustness, meaning that there exist some matrices for which the results are not accurate (even though most of the times they are).
43+
We are convinced that this issue is related to stability issues, as is fairly common in numerical linear algebra.
44+
4045
# How to run
4146
We provide an example of running code in the `script` folder.
4247
Assuming that you are in the root folder of the project, it sufficies to use
@@ -58,6 +63,14 @@ Notice, however, that due to Ulysse's problems with `MPI` the profiling for
5863
As a result, we also provide `submit.sh`, which is supposed to be run on a workstation.
5964
It executes `mpirun -np [n_procs] python scripts/profile_memory.py`, basically doing the same as the `submit.sbatch` script, but without using `SLURM`.
6065
Notice that it assumes that `shell/load_modules.sh` has already been executed (see the next section).
66+
Examples:
67+
```bash
68+
sbatch shell/subsmit.sbatch
69+
```
70+
and
71+
```bash
72+
./shell/submit.sh
73+
```
6174

6275
We also remark that the script to perform memory profiling `scripts/profile_memory.py` does not spam an `MPI` communicator, but is supposed to be called using `mpirun`. The reason for that is to provide a more extensive list of examples of how our package can be used.
6376

experiments/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
dim: 500
1+
dim: 200
22
density: 0.1
33
n_processes: 2
44
plot: false

scripts/mpi_running.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
import sys
77
import numpy as np
88
import argparse
9-
from pyclassify.utils import read_config, poisson_2d_structure, make_symmetric
9+
from pyclassify.utils import read_config, make_symmetric
1010
from pyclassify.eigenvalues import Lanczos_PRO
1111

1212

13-
seed = 8422
13+
seed = 84
1414
np.random.seed(seed)
1515

1616

@@ -59,11 +59,6 @@ def compute_eigvals(A, n_procs):
5959
density = kwargs["density"]
6060
n_procs = kwargs["n_processes"]
6161

62-
# You could use (for low values of dim, else accuracy suffers):
63-
# A = poisson_2d_structure(dim)
64-
# A_np = A.toarray()
65-
66-
# Alternatively, consider for instance:
6762
eig = np.arange(1, dim + 1)
6863
A = np.diag(eig)
6964
U = scipy.stats.ortho_group.rvs(dim)

scripts/profiling_memory.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
make_symmetric,
55
profile_numpy_eigvals,
66
profile_scipy_eigvals,
7-
poisson_2d_structure,
87
)
98
from pyclassify.parallel_tridiag_eigen import parallel_tridiag_eigen
109

@@ -20,7 +19,7 @@
2019
from mpi4py import MPI
2120

2221

23-
seed = 8422
22+
seed = 84
2423
np.random.seed(seed)
2524

2625

@@ -53,8 +52,13 @@
5352
# Now we build the matrix on rank 0
5453
# It is a scipy sparse matrix with the structure of a 2D Poisson problem matrix obtained using finite differences
5554
if rank == 0:
56-
A = poisson_2d_structure(dim)
57-
A_np = A.toarray()
55+
eig = np.arange(1, dim + 1)
56+
A = np.diag(eig)
57+
U = scipy.stats.ortho_group.rvs(dim)
58+
59+
A = U @ A @ U.T
60+
A = make_symmetric(A)
61+
A_np = A
5862
else:
5963
A_np = None
6064

scripts/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
t_s = time()
3737
eigvals, eigvecs = parallel_tridiag_eigen(
38-
main_diag, off_diag, comm=child_comm, min_size=1, tol_factor=1e-10
38+
main_diag, off_diag, comm=child_comm, min_size=1, tol_factor=1e-14
3939
)
4040
t_e = time()
4141

0 commit comments

Comments
 (0)