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 600 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.
Additionally, a small number of header-only extensions are provided for user convenience. See:
- linalg-std.h - Provide interop with some features of the C++ standard library
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 typedef
s 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 exactlyM
instances of typeT
explicit vec<T,M>(T s)
constructs all elements of the vector to the scalars
explicit vec<T,M>(const T * p)
constructs a vector by copying elements from an array which begins at addressp
explicit vec<T,M>(vec<U,M> v)
constructs a vector by casting all elements ofv
fromU
toT
T & operator[] (int i)
retrieves the element from thei
th row of the vector
mat<T,M,N>
represents a fixed-sized M
xN
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 exactlyN
column vectorsexplicit mat<T,M,N>(T s)
constructs all elements of the matrix to the scalars
explicit mat<T,M,N>(const T * p)
constructs a matrix by copying elements in column major order from an array which begins at addressp
explicit mat<T,M,N>(mat<U,M,N> m)
constructs a matrix by casting all elements ofm
fromU
toT
vec<T,M> & operator[] (int j)
retrieves thej
th column vector of the matrixvec<T,N> row (int i)
retrieves thei
th row of the matrix, as a vector
A variety of useful typedef
s 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:
+a
applies the unaryoperator +
to each element froma
-a
applies the unaryoperator -
to each element froma
~a
applies theoperator ~
to each element froma
!a
applies theoperator !
to each element froma
, producing a vector or matrix of boolsabs(a)
appliesstd::abs(...)
to each element froma
floor(a)
appliesstd::floor(...)
to each element froma
ceil(a)
appliesstd::ceil(...)
to each element froma
exp(a)
appliesstd::exp(...)
to each element froma
log(a)
appliesstd::log(...)
to each element froma
log10(a)
appliesstd::log10(...)
to each element froma
sqrt(a)
appliesstd::sqrt(...)
to each element froma
sin(a)
appliesstd::sin(...)
to each element froma
cos(a)
appliesstd::cos(...)
to each element froma
tan(a)
appliesstd::tan(...)
to each element froma
asin(a)
appliesstd::asin(...)
to each element froma
acos(a)
appliesstd::acos(...)
to each element froma
atan(a)
appliesstd::atan(...)
to each element froma
sinh(a)
appliesstd::sinh(...)
to each element froma
cosh(a)
appliesstd::cosh(...)
to each element froma
tanh(a)
appliesstd::tanh(...)
to each element froma
round(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+b
applies the binaryoperator +
to componentwise pairs of elements froma
andb
-
a-b
applies the binaryoperator -
to componentwise pairs of elements froma
andb
-
a*b
applies theoperator *
to componentwise pairs of elements froma
andb
-
a/b
applies theoperator /
to componentwise pairs of elements froma
andb
-
a%b
applies theoperator %
to componentwise pairs of elements froma
andb
-
a|b
applies theoperator |
to componentwise pairs of elements froma
andb
-
a^b
applies theoperator ^
to componentwise pairs of elements froma
andb
-
a&b
applies theoperator &
to componentwise pairs of elements froma
andb
-
a<<b
applies theoperator <<
to componentwise pairs of elements froma
andb
-
a>>b
applies theoperator >>
to componentwise pairs of elements froma
andb
-
min(a,b)
is equivalent to applyingstd::min(...)
to componentwise pairs of elements froma
andb
-
max(a,b)
is equivalent to applyingstd::max(...)
to componentwise pairs of elements froma
andb
-
fmod(a,b)
appliesstd::fmod(...)
to componentwise pairs of elements froma
andb
-
pow(a,b)
appliesstd::pow(...)
to componentwise pairs of elements froma
andb
-
atan2(a,b)
appliesstd::atan2(...)
to componentwise pairs of elements froma
andb
-
copysign(a,b)
appliesstd::copysign(...)
to componentwise pairs of elements froma
andb
-
equal(a,b)
applies theoperator ==
to componentwise pairs of elements froma
andb
, producing a vector or matrix of bools -
nequal(a,b)
applies theoperator !=
to componentwise pairs of elements froma
andb
, producing a vector or matrix of bools -
less(a,b)
applies theoperator <
to componentwise pairs of elements froma
andb
, producing a vector or matrix of bools -
greater(a,b)
applies theoperator >
to componentwise pairs of elements froma
andb
, producing a vector or matrix of bools -
lequal(a,b)
applies theoperator <=
to componentwise pairs of elements froma
andb
, producing a vector or matrix of bools -
gequal(a,b)
applies theoperator >=
to componentwise pairs of elements froma
andb
, producing a vector or matrix of bools
clamp(a,b,c)
clamps the elements ofa
to the lower boundb
and the upper boundc
These functions take a vector type and return a scalar value.
any(a)
returns true if any element ofa
is trueall(a)
returns true if all elements ofa
are 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 ina
maxelem(a)
returns the value of the largest element ina
argmin(a)
returns the zero-based index of the smallest element ina
argmax(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 vectorsa
andb
dot(a,b)
computes the dot product (also known as the inner or scalar product) of vectorsa
andb
length(a)
computes the length (magnitude) of vectora
length2(a)
computes the square of the length of vectora
normalize(a)
computes a vector of unit length with the same direction asa
distance(a,b)
computes the Euclidean distance between two pointsa
andb
distance2(a,b)
computes the square of the Euclidean distance between two pointsa
andb
uangle(a,b)
computes the angle, in radians, between unit length vectorsa
andb
angle(a,b)
computes the angle, in radians, between nonzero length vectorsa
andb
lerp(a,b,t)
linearly interpolates betweena
andb
using parametert
nlerp(a,b,t)
is equivalent tonormalize(lerp(a,b,t))
slerp(a,b,t)
performs spherical linear interpolation between unit length vectorsa
andb
using parametert
outerprod(a,b)
compute the outer product ofa
andb
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 productab
of quaternionsa
andb
qinv(q)
computes the multiplicative inverse of quaternionq
qconj(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 quaternionq
qnlerp(a,b,t)
performs normalized linear interpolation between the spatial rotations represented bya
andb
using parametert
qslerp(a,b,t)
performs spherical linear interpolation between the spatial rotations represented bya
andb
using parametert
qrot(q,v)
computes the result of rotating the vectorv
by quaternionq
qxdir(q)
computes the result of rotating the vector{1,0,0}
by quaternionq
qydir(q)
computes the result of rotating the vector{0,1,0}
by quaternionq
qzdir(q)
computes the result of rotating the vector{0,0,1}
by quaternionq
qmat(q)
computes a3
x3
rotation matrix with the same effect as rotating by quaternionq
These functions assume that a mat<T,M,N>
represents an M
xN
matrix, and a vec<T,M>
represents an M
x1
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 productab
of matricesa
andb
diagonal(a)
returns the diagonal of square matrixa
as a vectortranspose(a)
computes the transpose of matrixa
inverse(a)
computes the inverse of matrixa
determinant(a)
computes the determinant of matrixa
adjugate(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 4
x4
homogeneous matrices to represent general 3D transformations, and quaternions to represent 3D rotations.
rotation_quat(axis,angle)
constructs a rotation quaternion ofangle
radians about theaxis
vectorrotation_quat(matrix)
constructs a rotation quaternion from a3
x3
rotation matrixtranslation_matrix(translation)
constructs a transformation matrix which translates by vectortranslation
rotation_matrix(rotation)
constructs a transformation matrix which rotates by quaternionrotation
scaling_matrix(scaling)
constructs a transformation matrix which scales on the x, y, and z axes by the components of vectorscaling
pose_matrix(q,p)
constructs a transformation matrix which rotates by quaternionq
and translates by vectorp
frustum_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 ofa
using the binary functionf
in left-to-right ordermap(a, f)
produces a vector or matrix by passing elements froma
to unary functionf
zip(a, b, f)
produces a vector or matrix by passing componentwise pairs of elements froma
andb
to binary functionf