| Platform | Build Status |
|---|---|
| Visual Studio 2013, 2015, and 2017 | AppVeyor: |
| GCC 4.9 and Clang 3.7 | Travis CI: |
linalg.h is a single header public domain linear algebra library for C++11.
It is inspired by the syntax of popular shader languages and intended to serve as a lightweight (less than 400 total lines of code) alternative to projects such as GLM or Eigen in domains such as computer graphics, computational geometry, and physical simulation. It aims to be correct, complete, easy to use, readable, and quick to compile.
Existing linear algebra libraries are good but most are rather large, slowing down compile times and complicating inclusion into projects. linalg.h is a single file designed to be dropped directly into your source tree, and imposes no restrictions on your software from a technical, architectural, or legal standpoint.
Mostly due to broad availability of mostly compliant C++11 compilers. Earlier versions of C++ lack the features (lambdas, decltype, braced initializer lists, etc.) needed to implement linalg.h as generically and tersely as it has been. Later versions of C++ do provide useful features which could be used to make linalg.h even smaller and cleaner (generic lambdas and auto return types in particular), but do not appreciably improve the functionality of the library in its current form.
Most operator overloads and many function definitions in linalg.h use only a single line of code to define vector/vector, vector/scalar, scalar/vector, matrix/matrix, matrix/scalar, and scalar/matrix variations, for all possible element types and all dimensions of vector and matrix, and provide the behavior of applying the given operation to corresponding pairs of elements to produce a vector or matrix valued result. I chose to implement operator * in terms of elementwise multiplication for consistency with the rest of the library, and defined the mul function to provide matrix multiplication, alongside dot, cross, and qmul.
I wanted all instances of linalg.h types to model value semantics, and satisfy the EqualityComparable and LessThanComparable concepts from the C++ standard library. This means that code like if(a == b) ... behaves as it typically would, and data structures like std::set and std::map and functions like std::find and std::sort can be used with linalg.h types without modification.
- Data Structures
- Relational Operators
- Elementwise Functions
- Reduction Functions
- Vector Algebra
- Quaternion Algebra
- Matrix Algebra
- Factory Functions
- Higher Order Functions
The library is built on two fundamental template types, linalg::vec<T,M> and linalg::mat<T,M,N>, and provides a large set of typedefs of commonly used types in the linalg::aliases namespace, including the familiar float3, float4x4, int2, bool4 etc. Library support, and the convenience aliases, are currently provided for vectors of length 2 to 4, and matrices of between 2 to 4 columns and 2 to 4 rows.
vec<T,M> represents a fixed-length vector containing exactly M elements of type T. By convention, it is assumed to have column semantics. The following operations are available:
vec<T,M>()default constructs all elements of the vectorvec<T,M>(T, ...)constructs vector from exactlyMinstances of typeTexplicit vec<T,M>(T s)constructs all elements of the vector to the scalarsexplicit vec<T,M>(const T * p)constructs a vector by copying elements from an array which begins at addresspexplicit vec<T,M>(vec<U,M> v)constructs a vector by casting all elements ofvfromUtoTT & operator[] (int i)retrieves the element from theith row of the vector
mat<T,M,N> represents a fixed-sized MxN matrix, consisting of exactly N columns, each represented as an M length vector. The following operations are available:
mat<T,M,N>()default constructs all elements of the matrixmat<T,M,N>(vec<T,M>, ...)constructs matrix from exactlyNcolumn vectorsexplicit mat<T,M,N>(T s)constructs all elements of the matrix to the scalarsexplicit mat<T,M,N>(const T * p)constructs a matrix by copying elements in column major order from an array which begins at addresspexplicit mat<T,M,N>(mat<U,M,N> m)constructs a matrix by casting all elements ofmfromUtoTvec<T,M> & operator[] (int j)retrieves thejth column vector of the matrixvec<T,N> row (int i)retrieves theith row of the matrix, as a vector
A variety of useful typedefs are provided in namespace linalg::aliases, which can be brought into scope with a using declaration. The typedefs for float based vectors and matrices are shown below:
| vector | 2 columns | 3 columns | 4 columns | |
|---|---|---|---|---|
| 2 rows | float2 | float2x2 | float2x3 | float2x4 |
| 3 rows | float3 | float3x2 | float3x3 | float3x4 |
| 4 rows | float4 | float4x2 | float4x3 | float4x4 |
The general pattern for vectors and matrices of other types are shown in the following table:
| underlying type | vec<T,M> typedef | mat<T,M,N> typedef |
|---|---|---|
float | floatM | floatMxN |
double | doubleM | doubleMxN |
int | intM | intMxN |
bool | boolM | boolMxN |
unsigned | uintM | |
int16_t | shortM | |
uint16_t | ushortM | |
uint8_t | byteM |
The equivalence and relational operators on vec<T,M> are defined as though it were a std::array<T,M>. The equivalence and relational operators on mat<T,M,N> are defined as though it were a std::array<T,M*N>, with the elements laid out in column-major order. Therefore, both types satisfy the EqualityComparable and LessThanComparable concepts from the C++ standard library, and are suitable for use as the key type in std::set, std::map, etc.
Additionally, specializations are provided for std::hash<T> for both vec<T,M> and mat<T,M,N>, making them suitable for use as the key type in std::unordered_set and std::unordered_map.
A large number of functions and operator overloads exist which interpret vectors and matrices simply as fixed-size blocks of numbers. These operations will simply apply operations to each component of a vector or matrix, or to componentwise pairs of vectors and matrices of compatible size, and produce a new vector or matrix of the same size containing the results.
For any vector or matrix a, the following unary operations will result in a vector or matrix of the same size:
+aapplies the unaryoperator +to each element froma-aapplies the unaryoperator -to each element froma~aapplies theoperator ~to each element froma!aapplies theoperator !to each element froma, producing a vector or matrix of boolsabs(a)appliesstd::abs(...)to each element fromafloor(a)appliesstd::floor(...)to each element fromaceil(a)appliesstd::ceil(...)to each element fromaexp(a)appliesstd::exp(...)to each element fromalog(a)appliesstd::log(...)to each element fromalog10(a)appliesstd::log10(...)to each element fromasqrt(a)appliesstd::sqrt(...)to each element fromasin(a)appliesstd::sin(...)to each element fromacos(a)appliesstd::cos(...)to each element fromatan(a)appliesstd::tan(...)to each element fromaasin(a)appliesstd::asin(...)to each element fromaacos(a)appliesstd::acos(...)to each element fromaatan(a)appliesstd::atan(...)to each element fromasinh(a)appliesstd::sinh(...)to each element fromacosh(a)appliesstd::cosh(...)to each element fromatanh(a)appliesstd::tanh(...)to each element fromaround(a)appliesstd::round(...)to each element froma
For values a and b, there are a number of binary operations available, which produce vectors or matrices by performing the operation on elementwise pairs from a and b. If either a or b (but not both) are a scalar, the scalar is paired with each element from the other value, as described in the following table:
type of a | type of b | f(a,b) yields |
|---|---|---|
vec<T,M> | vec<T,M> | vec<T,M> { f(a[0], b[0]), f(a[1], b[1]), ... } |
vec<T,M> | T | vec<T,M> { f(a[0], b), f(a[1], b), ... } |
T | vec<T,M> | vec<T,M> { f(a, b[0]), f(a, b[1]), ... } |
mat<T,M,N> | mat<T,M,N> | mat<T,M,N> { {f(a[0][0], b[0][0]), f(a[0][1], b[0][1]), ...}, ... } |
mat<T,M,N> | T | mat<T,M,N> { {f(a[0][0], b), f(a[0][1], b), ...}, ... } |
T | mat<T,M,N> | mat<T,M,N> { {f(a, b[0][0]), f(a, b[0][1]), ...}, ... } |
The following operations are available:
-
a+bapplies the binaryoperator +to componentwise pairs of elements fromaandb -
a-bapplies the binaryoperator -to componentwise pairs of elements fromaandb -
a*bapplies theoperator *to componentwise pairs of elements fromaandb -
a/bapplies theoperator /to componentwise pairs of elements fromaandb -
a%bapplies theoperator %to componentwise pairs of elements fromaandb -
a|bapplies theoperator |to componentwise pairs of elements fromaandb -
a^bapplies theoperator ^to componentwise pairs of elements fromaandb -
a&bapplies theoperator &to componentwise pairs of elements fromaandb -
a<<bapplies theoperator <<to componentwise pairs of elements fromaandb -
a>>bapplies theoperator >>to componentwise pairs of elements fromaandb -
min(a,b)is equivalent to applyingstd::min(...)to componentwise pairs of elements fromaandb -
max(a,b)is equivalent to applyingstd::max(...)to componentwise pairs of elements fromaandb -
fmod(a,b)appliesstd::fmod(...)to componentwise pairs of elements fromaandb -
pow(a,b)appliesstd::pow(...)to componentwise pairs of elements fromaandb -
atan2(a,b)appliesstd::atan2(...)to componentwise pairs of elements fromaandb -
copysign(a,b)appliesstd::copysign(...)to componentwise pairs of elements fromaandb -
equal(a,b)applies theoperator ==to componentwise pairs of elements fromaandb, producing a vector or matrix of bools -
nequal(a,b)applies theoperator !=to componentwise pairs of elements fromaandb, producing a vector or matrix of bools -
less(a,b)applies theoperator <to componentwise pairs of elements fromaandb, producing a vector or matrix of bools -
greater(a,b)applies theoperator >to componentwise pairs of elements fromaandb, producing a vector or matrix of bools -
lequal(a,b)applies theoperator <=to componentwise pairs of elements fromaandb, producing a vector or matrix of bools -
gequal(a,b)applies theoperator >=to componentwise pairs of elements fromaandb, producing a vector or matrix of bools
clamp(a,b,c)clamps the elements ofato the lower boundband the upper boundc
These functions take a vector type and return a scalar value.
any(a)returns true if any element ofais trueall(a)returns true if all elements ofaare truesum(a)returns the scalar sum of all elements ina, as if writtena[0] + a[1] + ... a[M-1]product(a)returns the scalar product of all elements ina, as if writtena[0] * a[1] * ... a[M-1]minelem(a)returns the value of the smallest element inamaxelem(a)returns the value of the largest element inaargmin(a)returns the zero-based index of the smallest element inaargmax(a)returns the zero-based index of the largest element ina
These functions assume that a vec<T,M> represents a mathematical vector within an M-dimensional vector space.
cross(a,b)computes the cross product of vectorsaandbdot(a,b)computes the dot product (also known as the inner or scalar product) of vectorsaandblength(a)computes the length (magnitude) of vectoralength2(a)computes the square of the length of vectoranormalize(a)computes a vector of unit length with the same direction asadistance(a,b)computes the Euclidean distance between two pointsaandbdistance2(a,b)computes the square of the Euclidean distance between two pointsaandbuangle(a,b)computes the angle, in radians, between unit length vectorsaandbangle(a,b)computes the angle, in radians, between nonzero length vectorsaandblerp(a,b,t)linearly interpolates betweenaandbusing parametertnlerp(a,b,t)is equivalent tonormalize(lerp(a,b,t))slerp(a,b,t)performs spherical linear interpolation between unit length vectorsaandbusing parametertouterprod(a,b)compute the outer product ofaandb
These functions assume that a vec<T,4> represents a quaternion, expressed as xi + yj + zk + w. Note that quaternion multiplication is explicitly denoted via the function qmul, as operator * already refers to elementwise multiplication of two vectors.
qmul(a,b)computes the productabof quaternionsaandbqinv(q)computes the multiplicative inverse of quaternionqqconj(q)computesq*, the conjugate of quaternionq
Additionally, there are several functions which assume that a quaternion q represents a spatial rotation in 3D space, which transforms a vector v via the formula qvq*. The unit length quaternions form a double cover over spatial rotations. Therefore, the following functions assume quaternion parameters are of unit length and treat q as logically identical to -q.
qangle(q)computes the angle of rotation for quaternionq, in radiansqaxis(q)computes the axis of rotation for quaternionqqnlerp(a,b,t)performs normalized linear interpolation between the spatial rotations represented byaandbusing parametertqslerp(a,b,t)performs spherical linear interpolation between the spatial rotations represented byaandbusing parametertqrot(q,v)computes the result of rotating the vectorvby quaternionqqxdir(q)computes the result of rotating the vector{1,0,0}by quaternionqqydir(q)computes the result of rotating the vector{0,1,0}by quaternionqqzdir(q)computes the result of rotating the vector{0,0,1}by quaternionqqmat(q)computes a3x3rotation matrix with the same effect as rotating by quaternionq
These functions assume that a mat<T,M,N> represents an MxN matrix, and a vec<T,M> represents an Mx1 matrix. Note that matrix multiplication is explicitly denoted via the function mul, as operator * already refers to elementwise multiplication of two matrices.
mul(a,b)computes the productabof matricesaandbdiagonal(a)returns the diagonal of square matrixaas a vectortranspose(a)computes the transpose of matrixainverse(a)computes the inverse of matrixadeterminant(a)computes the determinant of matrixaadjugate(a)computes the adjugate of matrixa, which is the transpose of the cofactor matrix
These functions exist for easy interoperability with 3D APIs, which frequently use 4x4 homogeneous matrices to represent general 3D transformations, and quaternions to represent 3D rotations.
rotation_quat(axis,angle)constructs a rotation quaternion ofangleradians about theaxisvectorrotation_quat(matrix)constructs a rotation quaternion from a3x3rotation matrixtranslation_matrix(translation)constructs a transformation matrix which translates by vectortranslationrotation_matrix(rotation)constructs a transformation matrix which rotates by quaternionrotationscaling_matrix(scaling)constructs a transformation matrix which scales on the x, y, and z axes by the components of vectorscalingpose_matrix(q,p)constructs a transformation matrix which rotates by quaternionqand translates by vectorpfrustum_matrix(l,r,b,t,n,f)constructs a transformation matrix which projects by a specified frustumperspective_matrix(fovy,aspect,n,f)constructs a transformation matrix for a right handed perspective projection
The following higher order functions are provided by the library:
fold(a, f)combines the elements ofausing the binary functionfin left-to-right ordermap(a, f)produces a vector or matrix by passing elements fromato unary functionfzip(a, b, f)produces a vector or matrix by passing componentwise pairs of elements fromaandbto binary functionf