- Introduction
- The Cholesky algorithm
- Implementation Info and comparison with other methods
- Results
- Installation and virtual environment preparation
- Execution Guide
- References
In linear algebra, the Cholesky decomposition or Cholesky factorization is a decomposition of a Hermitian, positive-definite matrix into the product of a lower triangular matrix and its conjugate transpose, which is useful for efficient numerical solutions, e.g., Monte Carlo simulations and Linear least squares problems.
The Cholesky decomposition of a Hermitian positive-definite matrix
where
When
where
If a Hermitian matrix
However, if the rank of
The Cholesky algorithm, used to calculate the decomposition matrix L, is a modified version of Gaussian elimination.
The recursive algorithm starts with i := 1 and
At step i, the matrix
where
If we now define the matrix
(note that
where
Note that
We repeat this for i from 1 to n. After n steps, we get
If we write out the equation
we obtain the following:
and therefore the following formulas for the entries of L:
For complex and real matrices, inconsequential arbitrary sign changes of diagonal and associated off-diagonal elements are allowed. The expression under the square root is always positive if A is real and positive-definite.
For complex Hermitian matrix, the following formula applies:
So we can compute the (i, j) entry if we know the entries to the left and above. The computation is usually arranged in either of the following orders:
-
It starts from the upper left corner of the matrix L and proceeds to calculate the matrix row by row.
-
It starts from the upper left corner of the matrix L and proceeds to calculate the matrix column by column.
We found that there exist another, funny and much difficult to implement, method to compute the Cholesky Factorization. This was an idea of our Numerical Approximation course professor and consist in computing the factorization by proceeding in diagonal (antidiagonal to be precise).
This method starts from the upper left corner of the matrix L and proceeds to calculate the matrix antidiagonal by antidiagonal (see the img below for more details).
In order to demonstrate the speed of Cholesky Factorization over Gaussian Elimination we make a lot of test using a 5000 x 5000 matrix and log the execution time of the 2 method.
-
Cholesky Factorization time complexity:
$O(\dfrac{1}{3} n^3 + \dfrac{2}{3}n)$ -
Gaussian Elimination time complexity:
$O(n^3)$
The comparis was made using normal compilation and also compilation with JIT provided by Numba python package (see Numba).
The project is composed of 4 directory:
cholesky_factorization
: contains thecholesky.py
file that contains the cholesky implementations with all 3 methods described before.utils
: contains some python script used for- generate random matrix which are solvable factorizable using cholesky
- log execution time
- test and validation of obtained results
gaussian_elimination
: containsgaussian_elimination.py
script that implement gaussian elimination method.linear_system_solver
: containslinsys_solver.py
script that implement the resolution of linear system.
You can take the single script and refactor the code to use for any correlated implementation as you want.
For any doubt, question or issue you can open an issue or post it on Discussion tab.
In this section there are the result obtained with random 5000 x 5000 matrix in order to compare Gauss and Cholesky methods.
For each type of test we repeated it 3 times to obtain an avg value.
The execution times are expressed in milliseconds (ms).
Algorithm | Method | Matrix Size | JIT | Execution Time #1 | Execution Time #2 | Execution Time #3 | AVG Execution Time |
---|---|---|---|---|---|---|---|
Cholesky | COLUMN | 5000 | ❌ | 46000 | 45000 | 45000 | 45333.33 |
Cholesky | ROW | 5000 | ❌ | 73000 | 71000 | 70000 | 71333.33 |
Cholesky | DIAGONAL | 5000 | ❌ | 48000 | 49000 | 48000 | 48333.33 |
Algorithm | Method | Matrix Size | JIT | Execution Time #1 | Execution Time #2 | Execution Time #3 | AVG Execution Time |
---|---|---|---|---|---|---|---|
Cholesky | COLUMN | 5000 | ✅ | 23000 | 23000 | 23000 | 23000.00 |
Cholesky | ROW | 5000 | ✅ | 43000 | 43000 | 42000 | 42666.66 |
Cholesky | DIAGONAL | 5000 | ✅ | 25000 | 26000 | 26000 | 25666.66 |
Algorithm | Method | Matrix Size | JIT | Execution Time #1 | Execution Time #2 | Execution Time #3 | AVG Execution Time |
---|---|---|---|---|---|---|---|
Gauss | 5000 | ❌ | 51000 | 50000 | 50000 | 50333.33 |
Algorithm | Method | Matrix Size | AVG Execution Time (no JIT) | AVG Execution Time (JIT) | DIFF |
---|---|---|---|---|---|
Cholesky | COLUMN | 5000 | 45333.33 | 23000.00 | -22333.33 (49.26%) |
Cholesky | ROW | 5000 | 71333.33 | 42666.66 | -28666.67 (40.18%) |
Cholesky | DIAGONAL | 5000 | 48333.33 | 25666.66 | -22666.67 (46.89%) |
Cholesky Factorization Method | JIT | AVG Execution Time | Gaussian Elimination AVG Execution Time | DIFF |
---|---|---|---|---|
COLUMN | ❌ | 45333.33 | 50333.33 | -5000.00 (9.93%) |
ROW | ❌ | 71333.33 | 50333.33 | +21000.00 (41.72%) |
DIAGONAL | ❌ | 48333.33 | 50333.33 | -2000.00 (3.97%) |
COLUMN | ✅ | 23000.00 | 50333.33 | -27333.33 (54.30%) |
ROW | ✅ | 42666.66 | 50333.33 | -7666.66 (15.23%) |
DIAGONAL | ✅ | 25666.66 | 50333.33 | -24666.67 (49.00%) |
- Create a dir and download the project inside.
- Create a virtual env in that directory
virtualenv cholesky_env
- Activate venv to install project requirements
source cholesky_env/bin/activate
- Move to project dir and Install requirements
pip install -r requirements.txt
- Now you are ready to execute and test the project.
Script help page:
python main.py --help
usage: main.py [-h] [-tm {simple,find_limit,benchmark}] [-m {row,column,diagonal}] [--jit] [--seed SEED] [--size SIZE] [-alg {cholesky,gauss}] [-v]
options:
-h, --help show this help message and exit
-tm {simple,find_limit,benchmark}, --test_mode {simple,find_limit,benchmark}
Start the selected test mode.
simple: generate data, compute factorization/decomposition and resolve the Linear System.
find_limit: compute different Cholesky Factorization over bigger matrix (size * 2) every time, starting from a 100x100.
benchmark: generate data and only compute the factorization/decomposition.
This returns the execution time and saves results in a file
-m {row,column,diagonal}, --method {row,column,diagonal}
Select which Cholesky implementation to use.
--jit Enable JIT to enhance the performance.
--seed SEED Set the seed for the Random Number Generation.
--size SIZE Set the matrix size (if possible).
-alg {cholesky,gauss}, --algorithm {cholesky,gauss}
Choose the algorithm to use.
-v, --verbose Enable verbose mode.
Run a simple test:
The following line starts a simple test using a matrix 200x200
, with a seed of 20
using the Cholesky Factorization with the diagonal method/implementation.
python main.py -tm simple -alg cholesky -m diagonal --seed 20 --size 200
The following line starts the same test of the previous one with the Gaussian Decomposition algorithm.
python main.py -tm simple -alg gauss --seed 20 --size 200
Run a benchmark with JIT 🚀
This line runs the Cholesky Factorization algorithm with the row method/implementation, over a 10000x10000
matrix, with seed 20
, using JIT
compiling.
python main.py -tm benchmark --jit -alg cholesky -m row --seed 20 --size 10000
Cristian Cosci 🐔 | Nicolò Vescera 🦧 | Fabrizio Fagiolo 🐛 |