Eigen.js is a port of the Eigen C++ linear algebra library
It uses a WebAssembly compiled subset of the Eigen library, and implements a garbage collection mechanism to manage memory
An interactive documentation is available at eigen-js. Stress benchmarks can be found here
Eigen.js can be installed via npm or yarn
npm install eigen
yarn add eigen
In a node (v14) application or in the browser (using webpack)
// test.mjs
import eig from 'eigen';
(async () => {
await eig.ready;
let M = new eig.Matrix([[1, 2], [3, 4]]);
M.print("M");
M = M.inverse();
M.print("Minv");
eig.GC.flush();
})();
This minimal example can be found under ./example
To run it, execute
cd example
node test.mjs
Which results in
M
[[1.00, 2.00]
[3.00, 4.00]]
Minv
[[-2.00, 1.00]
[1.50, -0.50]]
The WebAssembly binary requires a manual memory management for objects allocated on the heap. Every time a matrix is created, it will be allocated on the heap and its memory won't be freed until its delete()
method is invoked
// test.mjs
import eig from 'eigen';
(async () => {
await eig.ready;
let M = new eig.Matrix([[1, 2], [3, 4]]); // Memory is allocated for M
M.print("M");
M.delete(); // Memory is freed here
M.print("M"); // This will trigger an error
})();
It can be cumbersome to call delete()
on every object, especially for chained computations. Take for example const I2 = eig.Matrix.identity(2, 2).matAdd(eig.Matrix.identity(2, 2))
. The identity matrix passed as an argument to matAdd(...)
will be allocated but never freed, which will leak memory. To make things easier to manage, eig.GC
keeps tracks of all the allocated objects on the heap and frees them all upon calling eig.GC.flush()
.
There could be instances where one would want to keep some matrices in memory while freeing a bunch of temporary ones used for computations. The method eig.GC.pushException(...matrices)
whitelists its arguments to prevent eig.GC.flush()
from flushing them. eig.GC.popException(...matrices)
cancels any previous whitelisting.
// test.mjs
import eig from 'eigen';
(async () => {
await eig.ready;
const x = new eig.Matrix([[1, 2], [3, 4]]);
eig.GC.pushException(x); // Whitelist x
// Perform some computations
const R = new eig.Matrix([[.1, 0], [.5, .1]]);
x.matAddSelf(R.matMul(eig.Matrix.ones(2, 2)));
// Free memory
eig.GC.flush();
x.print("x"); // x is still around!
})();
The documentation is available at eigen.js
Make sure Emscripten is intalled & activated in your terminal session
source path/to/emsdk/emsdk_env.sh
emcc -v
Install dependencies Eigen 3.3.9 and OSQP (optional, see below)
git submodule update --init --recursive
Now compile osqp for a Webassembly target
cd lib/osqp
mkdir build; cd build
emcmake cmake ..
emmake make
Once done, eigen.js can be compile to a wasm binary
# From the root directory
mkdir build
emcc -I lib/eigen -I lib/osqp/include -Isrc lib/osqp/build/out/libosqp.a -s DISABLE_EXCEPTION_CATCHING=0 -s ASSERTIONS=0 -O3 -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 --bind -o build/eigen_gen.js src/cpp/embind.cc
If you are not interested in the OSQP functionality, you can build without installing it with
emcc -D NO_OSQP -I lib/eigen -Isrc -s DISABLE_EXCEPTION_CATCHING=0 -s ASSERTIONS=0 -O3 -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 --bind -o build/eigen_gen.js src/cpp/embind.cc
The documentation is generated from classes descriptions using documentation.js
documentation build src/classes/ -f json -o docs/doc.json