Matrices are the workhorse of linear algebra. Eigen's Matrix and Array classes provide a comprehensive, type-safe API for creating, initializing, and manipulating matrices of any size and scalar type. Understanding the difference between Matrix (linear algebra operations) and Array (coefficient-wise operations) is key to writing correct and efficient numerical code.
Matrix Types in Eigen
Eigen distinguishes between two kinds of 2D containers:
| Type | Operations | Use Case |
|---|---|---|
Matrix | Linear algebra (matrix multiply, decompositions) | Geometry, linear systems, transformations |
Array | Coefficient-wise (element-by-element) | Signal processing, elementwise math |
Both support fixed-size and dynamic-size variants.
Fixed-Size Matrices
Fixed-size matrices have dimensions known at compile time:
Eigen::Matrix2d // 2x2 matrix of double
Eigen::Matrix3d // 3x3 matrix of double
Eigen::Matrix4d // 4x4 matrix of double (common for 3D transforms)
Eigen::Matrix2f // 2x2 matrix of float
Eigen::Matrix2cf // 2x2 matrix of complex<float>
Naming convention: Matrix<N><scalar> where N is the dimension (same rows and cols) and scalar is the type suffix.
Dynamic Matrices
Dynamic matrices have their dimensions set at runtime:
Eigen::MatrixXd // Dynamic matrix of double
Eigen::MatrixXf // Dynamic matrix of float
Eigen::MatrixXi // Dynamic matrix of int
// Create a 3x4 dynamic matrix
Eigen::MatrixXd m(3, 4);
Initializing Matrices
Zero Initialization
// Dynamic zero matrix
Eigen::MatrixXd X = Eigen::MatrixXd::Zero(3, 2);
// 3x2 matrix of all zeros
// Fixed-size zero matrix
Eigen::Matrix3d Z = Eigen::Matrix3d::Zero();
Comma Initialization
The comma initializer fills the matrix row by row, left to right:
// Fixed-size 2x2 matrix
Eigen::Matrix2d a;
a << 1, 2,
3, 4;
// a = | 1 2 |
// | 3 4 |
// Dynamic 2x2 matrix
Eigen::MatrixXd b(2, 2);
b << 2, 3,
1, 4;
Other Initialization Methods
// All ones
Eigen::MatrixXd ones = Eigen::MatrixXd::Ones(3, 3);
// Identity matrix
Eigen::MatrixXd I = Eigen::MatrixXd::Identity(4, 4);
// Random values
Eigen::MatrixXd rand = Eigen::MatrixXd::Random(3, 3);
// Constant value
Eigen::MatrixXd constant = Eigen::MatrixXd::Constant(2, 3, 5.0);
// 2x3 matrix where every element is 5.0
Coefficient Accessors
Access matrix elements using the (row, col) syntax (0-indexed):
#include <Eigen/Dense>
#include <iostream>
int main() {
Eigen::MatrixXd m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = m(1, 0) + m(0, 1); // 2.5 + (-1) = 1.5
std::cout << "Matrix m:\n" << m << std::endl;
// Matrix m:
// 3 -1
// 2.5 1.5
Eigen::VectorXd v(2);
v(0) = 4;
v(1) = v(0) - 1; // 3
std::cout << "Vector v:\n" << v << std::endl;
// Vector v:
// 4
// 3
return 0;
}
Matrix Information
Eigen::MatrixXd m(3, 4);
std::cout << m.rows() << std::endl; // 3
std::cout << m.cols() << std::endl; // 4
std::cout << m.size() << std::endl; // 12 (total elements)
std::cout << m.norm() << std::endl; // Frobenius norm
Matrix Operations
Eigen::MatrixXd A(2, 2);
A << 1, 2, 3, 4;
Eigen::MatrixXd B(2, 2);
B << 5, 6, 7, 8;
// Matrix addition and subtraction
Eigen::MatrixXd C = A + B; // element-wise addition
Eigen::MatrixXd D = A - B; // element-wise subtraction
// Matrix multiplication (linear algebra, not element-wise)
Eigen::MatrixXd E = A * B;
// E(0,0) = 1*5 + 2*7 = 19
// E(0,1) = 1*6 + 2*8 = 22
// E(1,0) = 3*5 + 4*7 = 43
// E(1,1) = 3*6 + 4*8 = 50
// Scalar multiplication
Eigen::MatrixXd F = 2.0 * A;
// Transpose
Eigen::MatrixXd T = A.transpose();
// T = | 1 3 |
// | 2 4 |
// Inverse (square matrices only)
Eigen::MatrixXd Inv = A.inverse();
// Determinant
double det = A.determinant();
Arrays vs. Matrices: Coefficient-wise vs. Linear Algebra
Eigen::MatrixXd m1(2, 2);
m1 << 1, 2, 3, 4;
Eigen::MatrixXd m2(2, 2);
m2 << 5, 6, 7, 8;
// Matrix multiplication (linear algebra)
Eigen::MatrixXd product = m1 * m2;
// [[19, 22], [43, 50]]
// Coefficient-wise multiplication (element by element)
Eigen::MatrixXd cwise = m1.cwiseProduct(m2);
// [[5, 12], [21, 32]]
// Using Array for coefficient-wise
Eigen::ArrayXXd a1 = m1.array();
Eigen::ArrayXXd a2 = m2.array();
Eigen::ArrayXXd cwise2 = a1 * a2; // element-wise *
Converting Between Matrix and Array
Eigen::MatrixXd mat = some_matrix;
Eigen::ArrayXXd arr = mat.array(); // Matrix -> Array
Eigen::MatrixXd mat2 = arr.matrix(); // Array -> Matrix
2D Arrays
Array types are directly available for 2D coefficient-wise work:
Eigen::ArrayXXd b1(2, 3);
b1 << 1, 2, 3,
4, 5, 6;
std::cout << "b1 =\n" << b1 << std::endl;
// b1 =
// 1 2 3
// 4 5 6
std::cout << "rows: " << b1.rows() << ", cols: " << b1.cols() << std::endl;
// rows: 2, cols: 3
// Coefficient-wise square
Eigen::ArrayXXd b1_sq = b1 * b1;
// b1_sq = [[1, 4, 9], [16, 25, 36]]
// Coefficient-wise sqrt
Eigen::ArrayXXd b1_sqrt = b1.sqrt();
Converting from STL Vector to Eigen Matrix
#include <Eigen/Dense>
#include <vector>
// Flat STL vector mapped as a column vector
int N = 100;
std::vector<float> v(N, 1.0f);
Eigen::VectorXf ev = Eigen::VectorXf::Map(&v[0], N);
// Flat STL vector mapped as a 2D matrix (row-major)
std::vector<double> flat(6, 1.0);
Eigen::Map<Eigen::MatrixXd> mat(flat.data(), 2, 3); // 2 rows, 3 cols
Converting from Eigen Matrix to STL Vector
Eigen::VectorXd ev(5);
ev << 1.0, 2.0, 3.0, 4.0, 5.0;
// Method 1: constructor from pointer range
std::vector<double> v1(ev.data(), ev.data() + ev.size());
// Method 2: resize and Map
std::vector<double> v2;
v2.resize(ev.size());
Eigen::Map<Eigen::VectorXd>(v2.data(), v2.size()) = ev;
Generic Template for Column Matrix to STL Vector
template<typename T>
std::vector<T> EigenColumnToVector(
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& matrix)
{
if (matrix.cols() != 1) {
throw std::invalid_argument("Matrix must have exactly one column");
}
std::vector<T> result;
result.resize(static_cast<std::size_t>(matrix.rows()));
for (Eigen::Index i = 0; i < matrix.rows(); ++i) {
result[static_cast<std::size_t>(i)] = matrix(i, 0);
}
return result;
}
Matrix Decompositions
Eigen provides a full set of matrix decompositions for solving linear systems:
Eigen::MatrixXd A(3, 3);
A << 2, 1, 1,
4, 3, 3,
8, 7, 9;
Eigen::VectorXd b(3);
b << 1, 1, 1;
// Solve Ax = b using LU decomposition (general case)
Eigen::VectorXd x = A.lu().solve(b);
// Solve using QR (more numerically stable)
Eigen::VectorXd x2 = A.colPivHouseholderQr().solve(b);
// Solve symmetric positive definite system (fastest)
Eigen::MatrixXd S = A.transpose() * A; // S is positive definite
Eigen::VectorXd x3 = S.llt().solve(A.transpose() * b);
Summary
Eigen Matrix Quick Reference:
+-------------------------+-------------------------------------------+
| Type | Description |
+-------------------------+-------------------------------------------+
| Matrix2d/3d/4d | Fixed N×N double matrix |
| MatrixXd | Dynamic double matrix |
| ArrayXXd | 2D array for coefficient-wise operations |
| ::Zero(r, c) | Zero matrix |
| ::Ones(r, c) | Ones matrix |
| ::Identity(n, n) | Identity matrix |
| ::Random(r, c) | Random matrix |
| m(i, j) | Element access (0-indexed) |
| m.rows() / m.cols() | Dimensions |
| m.transpose() | Transposed matrix |
| m.inverse() | Matrix inverse |
| m.determinant() | Determinant |
| m * n | Matrix multiplication |
| m.array() * n.array() | Coefficient-wise multiplication |
| Map(&v[0], r, c) | Zero-copy view of raw data |
+-------------------------+-------------------------------------------+
Conclusion
Eigen's Matrix and Array types provide a complete toolkit for 2D numerical data. Fixed-size matrices offer compile-time optimization and stack allocation. Dynamic matrices handle arbitrary dimensions at runtime. The distinction between Matrix (linear algebra semantics) and Array (coefficient-wise semantics) ensures you always get the mathematical operation you intend.
Combined with the vector operations from the previous post, you now have the full foundation for implementing any linear algebra algorithm — from simple matrix transformations to complex decompositions — using Eigen in C++.