A linear algebra library in C++ to do fast math.
Uses expression templates to build expression trees at compile time. Most expressions are lazily evaluated.
fastmatrix is header-only, simply add the location of fastmatrix.hpp to your include path while compiling.
For optimal speed, compile with the highest level of optimizations (-O3
on gcc/clang) and with assertions disabled (-DNDEBUG
on gcc/clang)
Example code:
#include "fastmatrix/fastmatrix.hpp"
#include <iostream>
using namespace fastmatrix;
int main () {
// Make a 3x3 matrix filled with 0.5
matrix<float> a(3, 3, 0.5); // (row, col, value)
matrix<float> b(3, 3, 0.4);
// Make an empty 3x3 matrix
matrix<float> result(3, 3); // (row, col)
// Basic arithmetic can be done easily
result = a + b;
result = a - b;
result = a * b;
// Element-wise arithmetic can be done too
// Here, 5 is subtracted from every element of a
result = a - 5;
// Expressions can be as long as you want them to be
result = 5 * a - result + b * 10.5 - result;
// Use eval to trigger eager evaluation.
// Here, it is beneficial to calculate (b + result)
// in advance to prevent repeated calculations
result = a * (b + result).eval();
// Getting and setting elements is possible
// All indexing is 0-based
std::cout << result(0, 1) << '\n'; // (row, column)
result.set_elt(0, 1, -1.5); // (row, column, new value)
std::cout << result(0, 1) << '\n';
// Printing a matrix is easy
std::cout << result << '\n';
return 0;
}
I ran some benchmarks on my PC, evaluating the performance of expressions in eager and lazy mode.
Eager mode is equivalent to a naive implementation of arithmetic expressions, creating a temporary variable after each operation. This behaviour was simulated by calling .eval()
after every operation.
Lazy mode constructs an expression at compile time using expression templates and only evaluates the expression when assigned to a matrix or .eval()
is called explicitly.
CPU: 4th Generation Intel(R) Core(TM) i7-4500U processor (4M Cache, up to 3.0 GHz)
Compiler: (Arch Linux) g++ (GCC) 8.2.1 20181127
- Capital letters represent matrices, Greek alphabets represent scalars.
- Each matrix is of size 10,000 × 1,000 and is filled with random floats.
- The metrics were obtained by running 10 trials.
- Each trial consisted of computing an expression 100 times.
Lazy | Eager (baseline) | |
---|---|---|
Time | 1.66 ± 0.06s | 6.28 ± 0.20s |
GFLOPS | 1.69 | 0.45 |
Lazy | Eager (baseline) | |
---|---|---|
Time | 0.88 ± 0.01s | 5.68 ± 0.04s |
GFLOPS | 3.16 | 0.49 |
To run the tests and benchmarks on Linux:
(Dependencies: CMake >= 3.10.1, g++ >= 7/clang++ >= 5)
-
Clone this repo
-
mkdir build && cd build
-
cmake ..
(Add-DBUILD_TESTS=OFF
to not build tests,-DBUILD_BENCHMARKS=OFF
to not build benchmarks). You can set the compiler to use by setting theCXX
environment variable before running cmake. -
cmake --build .
-
./tests
to run the tests and./bench/bench
to run the benchmarks
Run doxygen
to generate the documentation in the /docs
folder.