• Stars
    star
    131
  • Rank 275,867 (Top 6 %)
  • Language
    C++
  • License
    BSD 2-Clause "Sim...
  • Created over 12 years ago
  • Updated over 11 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Light-weight and Fast Template Matrix Library

Welcome to LightMatrix

LightMatrix is a C++ template library for matrix computation, which provides a unique combination of design-time productivity and run-time performance. With this library, user can write codes using a set of friendly APIs (just like in MATLAB). These codes will then be transparently translated to highly optimized routines (at compile-time), through a meta-programming engine.

Important Note: LightMatrix heavily uses new features of the latest C++11 standard, including r-value reference, variadic templates, automatic type inference, and C++11 math. To compile this library, you need to have a compiler with good C++11 support. In particular, this library has been tested on Clang 4.0 (Mac OS X) and GCC 4.7 (Linux)

Overview

Relying a carefully designed core framework, LightMatrix has a series of nice properties. Here is a brief summary:

  • LightMatrix is easy to use: one can perform computation easily using natural expressions
  • LightMatrix is efficient: high level codes will be mapped to tight loops of highly optimized SIMD instructions through meta-programming. No temporary matrices will be created in most cases.
  • LightMatrix is convenient: it supports various ways to access elements and sub parts of a matrix.
  • LightMatrix is versatile: it offers a broad range of functions out of box, which range from elementary functions, matrix reduction, to linear algebra.
  • LightMatrix works nicely with other libraries: it can directly work on external memories (without copying). Interfaces to work with STL vectors and MATLAB arrays are provided.
  • LightMatrix supports kernel-based computation: it has elegant syntax to define kernels and apply them to matrices in an element-wise manner. This provides a very efficient way for multi-input multi-output computation.
  • LightMatrix is extensible: one can easily introduce new matrix expressions and evaluation methods.
  • LightMatrix is light-weight: it is a pure header library, and it does not rely on third-party libraries such as BOOST.
  • LightMatrix is reliable: quality assured through extensive unit testing.

Below are some specific examples/explanations to illustrate these features.

LightMatrix is easy to use

You can easily make matrices and perform computation using matrix expressions.

using namespace lmat;

// generate a 2-by-3 matrix by inserting elements in row-major order
dense_matrix<double> a(2, 4, rm_({1., 2., 3., 4., 5., 6., 7., 8.}));
	
// generate a matrix by copying elements from a memory source 
double src[] = {1., 2., 3., 4., 5., 6., 7., 8.};
dense_matrix<double> b(2, 4, copy_from(src));
	
// do some computation
a += exp(b) * log(a + 1.0);

LightMatrix is efficient

When AVX is enabled, the last statement above would be translated transparently at compile time to something like the following: (note: it also supports SSE)

v1 = _mm256_set1_pd(1.0);
for (index_t i = 0; i < a.nelems(); i += 4) 
{
	va = _mm256_load_pd(a.ptr_data() + i);
	vb = _mm256_load_pd(b.ptr_data() + i);
	t1 = __svml_exp4(vb);
	t2 = __svml_log4(_mm256_add_pd(va, v1));
	r = _mm256_add_pd(t1, t2);
	_mm256_store_pd(a.ptr_data() + i, r); 
}

The performance is comparable to hand-optimized SIMD codes. (Node: __svml_exp4 and __svml_log4 are routines to compute exp and log on AVX vectors.) When explicitly requested, it can also generate multi-threaded codes using OpenMP.

LightMatrix is convenient

LightMatrix supports a variety of convenient ways to access to elements and parts of a matrix. You may access individual elements using either subscripts or linear indices:

// Let a be a matrix 
x = a(i, j);   // access the element at i-th row and j-th column
x = a[idx];    // access the idx-th element over the entire matrix

You may access a row or a column of a matrix

c = a.column(j);   // c is a view of the j-th column
r = a.row(i);      // r is a view of the i-th row

Miss MATLAB's colon syntax? LightMatrix provides similar ways for you to access parts of a matrix

// get a view of a sub-matrix
u = a(colon(i0, i1), colon(j0, j1));  

// get a view of n consecutive columns from the j-th one
v = a(whole(), range(j, n)); 

// select a certain set of rows
si = dense_col<index_t>({3, 0, 2, 4, 6});
s = select_rows(a, si);

// add a value to each element on the diagonal
a.diag() += 2.0;

LightMatrix is versatile

It comprises a broad range of functions for various kinds of computation (out of box):

  • matrix manipulation, such as vector repeating and matrix transposition

  • element-wise arithmetics, logical operations, comparison, and conditional selection

  • element-wise elemental functions (including all those in C99/C++11 math)

  • reduction functions (including sum, mean, maximum, minimum, minmax, norms, etc) in three forms: whole-matrix, column-wise, and row-wise reduction.

  • linear algebraic computation:

    • matrix-vector and matrix-matrix multiplication
    • matrix factorization: LU, QR, and Cholesky
    • eigenvalue and eigenvector
    • singular value decomposition
    • solving linear equations and least square problems
  • random matrices from different distributions

LightMatrix works nicely with other libraries

Practical applications often involve multiple libraries. We realize this and consider interoperability with other libraries as an essential feature from the very beginning.

The matrix class exposes the raw data pointer, so that you can use other functions, in particular those in C libraries, to process the data in a matrix, as

a.ptr_data();  // returns the pointer to the base address
a.ptr_col(j);  // returns the pointer to the base of the j-th column

You may also construct a matrix directly on external memory blocks:

// let p be a pointer to some contiguous memory region
ref_matrix<double> a(p, m, n);  // construct an m-by-n matrix directly on p

// when the stride between consecutive columns is stride (instead of m)
ref_block<double> b(p, m, n, stride); 

LightMatrix works well with STL vector and MATLAB mxArray

// directly adapts std::vector to a LightMatrix column vector (no copying)
std::vector<double> v {1.0, 2.0, 3.0};
std::dense_col<double> r = sin(as_col(v)  * 2.0);

// creates a LightMatrix view on a MATLAB array (handy for writing mex)
const mxArray *mx = prhs[0];
ref_matrix<double> a = view2d<double>(mx);

LightMatrix supports kernel-based computation

In complex numerical computation that involves multiple inputs and outputs, kernel-based computation is often more efficient than matrix expressions.

Suppose you want to do the computation as expressed by the following matrix expressions:

u = sqr(a + b) - sqr(a - b); 
v = sqr(a + b) + sqr(a - b); 

But then sqr(a + b) and sqr(a - b) are respectively calculated twice. Whereas one can temporarily store the the intermediate results, this way demands more memory and requires scanning each matrix more than once. The more optimal way is to apply a multi-input-multi-output kernel, as

// define a kernel (as a generic functor)
template<typename T>
struct my_kernel
{
	void operator() (const T& a, const T& b, T& u, T& v) const 
	{
		T t1 = sqr(a + b);
		T t2 = sqr(a - b);
		u = t1 - t2;
		v = t1 + t2;
	}
};

// introduce SIMD support
LMAT_DEF_SIMD_SUPPORT( my_kernel )

// apply the kernel in an element-wise way to matrices
ewise(my_kernel())(in_(a), in_(b), out_(u), out_(v));

LightMatrix will translate this (at compile-time) into tight loops of SIMD instructions, without creating any temporary matrices.

LightMatrix is extensible

LightMatrix is designed with extensibility in mind. Developers can easily extend the library by introducing new matrix expressions or even new evaluation paradigms, following the Developer Guide.

LightMatrix is light-weight

LightMatrix is a pure header library. To use it, just check it out from GitHub, and include the relevant headers in your code.

Note that linking with third-party libraries is needed for some functions. For example, you may have to link your code to BLAS/LAPACK or MKL when using the linear algebra module.

LightMatrix is reliable

The quality of the library is assured through thousands of unit-test cases.