Numerical Computing with Eigen
Reviewed & published by Brayan K
Robotics, computer vision, graphics, and machine learning all run on linear algebra — vectors and matrices, multiplied and solved at speed. Eigen is the go-to C++ library for exactly that: fast, expressive, and header-only. By the end of this lesson you'll create fixed and dynamic Matrix and Vector types, fill them with the comma initializer, multiply and transpose them, take dot products, and solve a system of linear equations.
Part of the free C++ course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn
- Create Matrix and Vector types (fixed and dynamic size)
- Fill entries with the comma initializer (<<)
- Do arithmetic and true matrix multiplication with *
- Use .transpose(), .inverse(), and .dot()
- Tell the Matrix and Array (coefficient-wise) interfaces apart
- Solve a linear system A x = b
💡 Real-World Analogy
Think of Eigen as a spreadsheet engine for C++. A Vector is a single column of numbers; a Matrix is a grid of rows and columns. Just as a spreadsheet lets you add two ranges, multiply them, or transpose a block with one formula, Eigen lets you write a * b or a.transpose() and have it mean the correct linear-algebra operation. And like choosing a fixed table size versus a table that grows, you pick a fixed-size type (Matrix3d) when you know the dimensions, or a dynamic one (MatrixXd) when they depend on the data.
1. Matrices and Vectors
Eigen's core types are Matrix and Vector. Convenient typedefs name the common ones: Vector3d is a 3-element column vector of double, Matrix3d a 3x3 matrix of double. These are fixed-size — their dimensions are known at compile time, which lets Eigen optimize hard and often skip heap allocation. For sizes decided at run time, use dynamic types like MatrixXd and VectorXd (the X means "any size"). You index elements with m(row, col).
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// Fixed-size types: dimensions known at compile time.
Vector3d v(1.0, 2.0, 3.0); // a 3-element column vector of double
Matrix3d m = Matrix3d::Zero(); // a 3x3 matrix, all zeros
m(0, 0) = 5.0; // set element at row 0, col 0
m(1, 2) = 7.0; // row 1, col 2
cout << "v =\n" << v << "\n\n";
cout << "m =\n" << m << endl;
// v prints as a column: 1 / 2 / 3
// m prints as a 3x3 grid with 5 at top-left and 7 at row1,col2
return 0;
}
// ⚠️ No expected-output panel for this one, on purpose.
// Eigen is a header-only library you install yourself, so this build has
// no copy and cannot machine-check the output the way the rest of the
// course is checked. Install it (apt install libeigen3-dev, or vcpkg/brew)
// and compile with -I/usr/include/eigen3.To fill a matrix with literal values, use Eigen's comma initializer: stream values in with <<, and they fill the matrix in row-major order (left to right, top to bottom).
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// The COMMA INITIALIZER fills entries in ROW-MAJOR order.
Matrix2d a;
a << 1, 2,
3, 4; // row 0: [1 2], row 1: [3 4]
Vector3d v;
v << 10, 20, 30;
cout << "a =\n" << a << "\n\n";
cout << "v =\n" << v << endl;
return 0;
}
// ⚠️ No expected-output panel for this one, on purpose.
// Eigen is a header-only library you install yourself, so this build has
// no copy and cannot machine-check the output the way the rest of the
// course is checked. Install it (apt install libeigen3-dev, or vcpkg/brew)
// and compile with -I/usr/include/eigen3.2. Arithmetic and Matrix Multiplication
On Matrix objects, the operators follow linear-algebra rules. + and - are element-wise, but * is true matrix multiplication (rows times columns), not element-by-element. .transpose() swaps rows and columns, and for vectors .dot() gives the scalar dot product.
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
Matrix2d a; a << 1, 2,
3, 4;
Matrix2d b; b << 5, 6,
7, 8;
// For Matrix objects, '*' is TRUE matrix multiplication.
Matrix2d product = a * b; // [[19 22], [43 50]]
Matrix2d sum = a + b; // element-wise add
cout << "a * b =\n" << product << "\n\n";
cout << "a + b =\n" << sum << "\n\n";
cout << "a^T =\n" << a.transpose() << endl; // rows<->cols
return 0;
}
// ⚠️ No expected-output panel for this one, on purpose.
// Eigen is a header-only library you install yourself, so this build has
// no copy and cannot machine-check the output the way the rest of the
// course is checked. Install it (apt install libeigen3-dev, or vcpkg/brew)
// and compile with -I/usr/include/eigen3.Your turn. Two perpendicular unit vectors should have a dot product of zero. Fill in the blank with the dot-product call:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
Vector3d a(1.0, 0.0, 0.0);
Vector3d b(0.0, 1.0, 0.0);
// 🎯 YOUR TURN — compute the DOT PRODUCT of a and b.
double d = ___; // 👉 a.dot(b)
cout << "a . b = " << d << endl;
// ✅ Expected output: a . b = 0
// (These two vectors are perpendicular, so their dot product is 0.)
return 0;
}🧩 Reorder Challenge
These lines should build a 2x2 matrix, fill it, and print its transpose. Put them in the right order:
A. Matrix2d m;
B. m << 1, 2,
C. 3, 4;
D. std::cout << m.transpose() << std::endl;Correct order: A → B → C → D
Declare the matrix (A), begin the comma initializer with the first row (B), finish it with the second row (C), then print the transpose (D).
3. Matrix vs Array: Two Meanings of *
Sometimes you want element-by-element math, not linear algebra. Eigen separates these into the Matrix interface (linear-algebra operators) and the Array interface (coefficient-wise operators). Call .array() on a matrix to get array semantics — now * multiplies element by element — and .matrix() to switch back. Same data, two operator meanings.
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
Matrix2d a; a << 1, 2,
3, 4;
Matrix2d b; b << 5, 6,
7, 8;
// MATRIX * is linear algebra (matrix product).
Matrix2d mat = a * b; // [[19 22],[43 50]]
// .array() switches to COEFFICIENT-WISE: now * is element-by-element.
Matrix2d elem = (a.array() * b.array()).matrix(); // [[5 12],[21 32]]
cout << "matrix product =\n" << mat << "\n\n";
cout << "element-wise =\n" << elem << endl;
return 0;
}
// ⚠️ No expected-output panel for this one, on purpose.
// Eigen is a header-only library you install yourself, so this build has
// no copy and cannot machine-check the output the way the rest of the
// course is checked. Install it (apt install libeigen3-dev, or vcpkg/brew)
// and compile with -I/usr/include/eigen3.4. Solving Linear Systems
A core task in numerical computing is solving A x = b for the unknown vector x. You could write x = A.inverse() * b, but explicitly inverting a matrix is slower and less numerically stable. The recommended way is a matrix decomposition that solves directly — for a general matrix, A.colPivHouseholderQr().solve(b).
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// Solve A x = b for x.
// 2x + y = 5
// x + 3y = 10
Matrix2d A; A << 2, 1,
1, 3;
Vector2d b; b << 5, 10;
// Preferred: a decomposition solves directly (stable & efficient).
Vector2d x = A.colPivHouseholderQr().solve(b);
cout << "x =\n" << x << endl; // x = 1, y = 3
// Alternative (less preferred): Vector2d x = A.inverse() * b;
return 0;
}
// ⚠️ No expected-output panel for this one, on purpose.
// Eigen is a header-only library you install yourself, so this build has
// no copy and cannot machine-check the output the way the rest of the
// course is checked. Install it (apt install libeigen3-dev, or vcpkg/brew)
// and compile with -I/usr/include/eigen3.🔎 Deep Dive: header-only and expression templates
Eigen is header-only: there is no compiled .lib or .so to link. You add its include directory and write #include <Eigen/Dense>; the compiler does the rest. That makes it trivial to drop into a project — but because it is third-party, it must first be present on the include path.
Under the hood, Eigen uses expression templates. An expression like a + b + c doesn't build two temporary matrices; instead it builds a small compile-time description of the computation and evaluates the whole thing in one pass when assigned. That is a big part of why Eigen is both expressive and fast.
MatrixXd a(1000,1000), b(1000,1000), c(1000,1000);
// No temporaries for each '+': evaluated in a single fused loop.
MatrixXd result = a + b + c;Pro Tips
- 💡 Use fixed-size types for small, known sizes (Vector3d, Matrix4d) — they are faster and often allocation-free.
- 💡 Remember * on a Matrix is matrix multiplication; reach for .array() when you want element-wise.
- 💡 Prefer decompositions over .inverse() for solving systems — they are more accurate and faster.
- 💡 Watch dimensions: matrix multiplication needs the inner dimensions to match, or Eigen asserts at run time.
🧠 Quick Recall
1. What does Matrix3d represent?
A fixed-size 3x3 matrix of double.
2. For two Eigen matrices, what does a * b compute?
The matrix product — not element-wise. Use a.array() * b.array() for element-wise.
3. What is the better way to solve A x = b?
A decomposition such as A.colPivHouseholderQr().solve(b), rather than A.inverse() * b.
Common Errors (and the fix)
- Expecting * to be element-wise: on a Matrix, a * b is the matrix product. Use a.array() * b.array() for coefficient-wise multiplication.
- Mismatched dimensions: matrix multiplication requires the inner dimensions to agree; otherwise Eigen triggers a runtime assertion.
- Under-filling the comma initializer: the number of values must exactly match the matrix size, or Eigen asserts. Count your entries.
- Inverting to solve: A.inverse() * b works but is slower and less stable than a decomposition's .solve(b).
- Forgetting the include / namespace: you need #include <Eigen/Dense> and the Eigen namespace (or Eigen:: qualifiers).
📋 Quick Reference
| Task | Code |
|---|---|
| Fixed 3-vector | Vector3d v(1, 2, 3); |
| Dynamic matrix | MatrixXd m(rows, cols); |
| Fill values | m << 1, 2, 3, 4; |
| Matrix multiply | auto c = a * b; |
| Transpose | m.transpose() |
| Dot product | a.dot(b) |
| Element-wise | a.array() * b.array() |
| Solve A x = b | A.colPivHouseholderQr().solve(b) |
Mini-Challenge: rotate a 2D point
Build a 90-degree rotation matrix with the comma initializer, multiply it by a point vector, and print the rotated result. This is matrix-times-vector in action.
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
// 🎯 MINI-CHALLENGE: rotate a 2D point
// 1. Build a 2x2 rotation matrix R for 90 degrees:
// R << 0, -1,
// 1, 0;
// (use the comma initializer)
// 2. Make a Vector2d p = (1, 0).
// 3. Compute rotated = R * p; (matrix * vector)
// 4. Print 'rotated'.
//
// ✅ Expected output (a column vector):
// 0
// 1
int main() {
// your code here
return 0;
}🎉 Lesson Complete
- ✅ Eigen is a header-only C++ library for linear algebra
- ✅ Matrix and Vector come in fixed (Matrix3d) and dynamic (MatrixXd) sizes
- ✅ The comma initializer << fills entries in row-major order
- ✅ On a Matrix, * is matrix multiplication; .array() switches to element-wise
- ✅ .transpose(), .inverse(), and .dot() cover common operations
- ✅ Solve A x = b with a decomposition's .solve(b), not by inverting
- 🎓 Course complete — you have reached the end of the C++ track. Congratulations!
Practice quiz
What kind of library is Eigen?
- A header-only C++ template library for linear algebra
- A compiled library you must link against
- A Python package
- A part of the C++ standard library
Answer: A header-only C++ template library for linear algebra. Eigen is a header-only C++ template library, so you include its headers and need no separate linking step.
What does Eigen::Matrix3d represent?
- A 3D graphics object
- A dynamic-size matrix of ints
- A fixed-size 3x3 matrix of doubles
- A 3-element vector
Answer: A fixed-size 3x3 matrix of doubles. Matrix3d is a convenience typedef for a fixed-size 3x3 matrix of double.
What is the difference between fixed-size and dynamic-size matrices in Eigen?
- Fixed-size are always faster to compile
- Fixed-size have dimensions known at compile time; dynamic-size are sized at run time
- Dynamic-size cannot be multiplied
- There is no difference
Answer: Fixed-size have dimensions known at compile time; dynamic-size are sized at run time. Fixed-size dimensions are compile-time constants (often stack-allocated); dynamic-size (MatrixXd) are chosen at run time.
What does the comma initializer do, as in m << 1, 2, 3, 4;?
- Declares matrix dimensions
- Prints the matrix
- Concatenates matrices
- Fills the matrix entries in row-major order
Answer: Fills the matrix entries in row-major order. Eigen's comma initializer fills coefficients row by row in the order written.
Which operator multiplies two Eigen matrices as matrix multiplication?
- The * operator
- The % operator
- The .array() method
- The .dot() method
Answer: The * operator. For Matrix objects, operator* performs true matrix (not element-wise) multiplication.
What does a.dot(b) compute for two vectors?
- Their element-wise product
- Their scalar dot product
- A matrix
- Their cross product
Answer: Their scalar dot product. .dot() returns the scalar dot (inner) product of two vectors.
What does m.transpose() return?
- The determinant of m
- m scaled by -1
- The inverse of m
- A view of m with rows and columns swapped
Answer: A view of m with rows and columns swapped. .transpose() gives the transpose, swapping rows and columns.
In Eigen, what is the difference between the Matrix and Array interfaces?
- Array cannot store doubles
- Array uses linear-algebra operators; Matrix uses element-wise ones
- Matrix uses linear-algebra operators; Array makes * and others element-wise (coefficient-wise)
- They are identical
Answer: Matrix uses linear-algebra operators; Array makes * and others element-wise (coefficient-wise). Matrix operators are linear-algebra (so * is matrix product); Array operators are coefficient-wise, so * multiplies element by element.
How do you typically solve a linear system A x = b in Eigen?
- By calling A.solve(b) directly
- By computing A.inverse() * b, or better, using a decomposition's .solve(b)
- By calling b / A
- It is not possible in Eigen
Answer: By computing A.inverse() * b, or better, using a decomposition's .solve(b). You can write A.inverse() * b, but using a decomposition such as colPivHouseholderQr().solve(b) is preferred for accuracy and speed.
Why is Eigen described as header-only?
- You include its headers and compile directly, with no library to link
- It has no documentation
- It only supports headers up to C++11
- It only works in header files
Answer: You include its headers and compile directly, with no library to link. Being header-only means you just add the include path and #include the headers; there is no compiled .lib or .so to link.
Continue this course
- Previous: Coroutines (C++20)
- Next: optional, variant & any (C++17) — Type-safe maybe-values, sum types and type-erased values
- Quick reference: C++ cheat sheet
Frequently asked questions
What is Eigen and what is it used for?
Eigen is a popular, high-performance C++ template library for linear algebra: vectors, matrices, and the operations on them. It is widely used in robotics, computer vision, graphics, machine learning, and scientific computing because it is fast, expressive, and header-only.
Do I need to install or link anything to use Eigen?
Eigen is header-only, so there is no compiled library to link. You download the headers, add the include directory to your compiler's path, and write #include <Eigen/Dense>. Because it is third-party, it may not be installed on every system, but using it requires no separate build or link step.
What is the difference between fixed-size and dynamic-size types?
Fixed-size types such as Matrix3d or Vector3d have their dimensions baked in at compile time, which lets the compiler optimize aggressively and often avoid heap allocation. Dynamic-size types such as MatrixXd and VectorXd choose their dimensions at run time and store their data on the heap. Use fixed-size for small, known sizes and dynamic-size when the size depends on input.
What is the difference between the Matrix and Array interfaces?
On a Matrix, operators follow linear-algebra rules, so * is matrix multiplication and the type tracks dimensions accordingly. The Array interface makes the same operators coefficient-wise, so * multiplies element by element. You switch between them with .array() and .matrix() to pick whichever meaning you need for a given expression.
How should I solve a system of linear equations?
You can write x = A.inverse() * b, but explicitly inverting a matrix is usually slower and less numerically stable. The recommended approach is a matrix decomposition, for example A.colPivHouseholderQr().solve(b) or, for symmetric positive-definite matrices, an LLT decomposition. These solve the system directly without forming the inverse.