Clojure/Java Matrix Library Performance Comparison
17 May 2023This is a quick performance comparison of the Clojure core.matrix library and the Efficient Java Matrix Library. Because core.matrix uses the VectorZ Java library as a backend, direct calls to VectorZ were also included in the comparison. Finally I added fastmath to the comparison after it was pointed out to me by the developer. The criterium 0.4.6 benchmark library was used to measure the performance of common matrix expressions. The Clojure version was 1.11.1 and OpenJDK runtime version was 17.0.6. Here are the results running it on an AMD Ryzen 7 4700U with a turbo speed of 4.1 GHz:
op | core. matrix 0.63.0 | ejml-all 0.43 | vectorz- clj 0.48.0 | fastmath 2.2.1 |
---|---|---|---|---|
make 4x4 matrix | 675 ns | 135 ns | 50.5 ns | 13.1 ns |
make 4D vector | 299 ns | 47.6 ns | 9.27 ns | 3.67 ns |
add 4D vectors | 13.5 ns | 18.2 ns | 9.02 ns | 4.29 ns |
inverse matrix | 439 ns | 81.4 ns | 440 ns | 43.6 ns |
elementwise matrix multiplication | 64.9 ns | 29.0 ns | 29.1 ns | 13.7 ns |
matrix multi plication | 102 ns | 74.7 ns | 100 ns | 22.4 ns |
matrix-vector multiplication | 20.9 ns | 31.2 ns | 19.1 ns | 6.46 ns |
vector dot product | 6.56 ns | 6.90 ns | 4.46 ns | 6.36 ns |
vector norm | 10.1 ns | 11.4 ns | no support? | 3.74 ns |
matrix determinant | 170 ns | 7.35 ns | 166 ns | 7.67 ns |
matrix element access | 4.14 ns | 3.35 ns | 3.26 ns | 3.53 ns1 |
get raw data array | 12.0 ns | 3.00 ns | 11.9 ns | 13.2 ns1 |
1requires fastmath 2.2.2-SNAPSHOT or later
See matperf.clj for source code of benchmark script.
Comparing EJML with a mix of core.matrix and direct calls to vectorz:
- EJML has support for both single and double precision floating point numbers
- it uses single column matrices to represent vectors leading to slower matrix-vector multiplication
- it has a fast 4x4 matrix inverse
- it does not come with a Clojure wrapper
- it offers fast access to raw data
- it does not support multi-dimensional arrays
Comparing EJML with fastmath:
- EJML has support for matrices larger than 4x4
- EJML gives you access to the matrix as a flat floating point array (fastmath will add support in the future)
- EJML is mostly slower
The implementations of the libraries are all quite impressive with custom optimisations for small matrices and vectors. Note that I didn’t include Neanderthal in the comparison because it is more suitable for large matrices.
I hope you find this comparison useful.
Update:
The large performance difference for matrix inversion is probably because EJML has custom 4x4 matrix classes while VectorZ stops at 3x3. Here is a performance comparison of matrix inverse for 3x3, 4x4, and 5x5 matrices:
op | core. matrix 0.63.0 | ejml-all 0.43 | vectorz- clj 0.48.0 | fastmath 2.2.1 |
---|---|---|---|---|
3x3 matrix inverse | 13.0 ns | 48.3 ns | 12.2 ns | 10.8 ns |
4x4 matrix inverse | 471 ns | 98.3 ns | 465 ns | 50.3 ns |
5x5 matrix inverse | 669 ns | 172 ns | 666 ns | not supported |
Further updates:
- posted it on Reddit
- weavejester/euclidean is a small library implementing small square matrices and vectors.
- play-cljc comes with a matrix library as well.
- there is also ojalgo which according to the Java Matrix Benchmark is the fasted pure Java linear algebra library.
- fastmath is a very fast Clojure library which provides double-precision matrix operations up to dimension 4.
- 18/01/2024: fastmath version 2.3.0 was released