Numerical Computing with Eigen
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.
Learn Numerical Computing with Eigen in our free C++ course — an interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 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) .
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).
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.
Your turn. Two perpendicular unit vectors should have a dot product of zero. Fill in the blank with the dot-product call:
🧩 Reorder Challenge
These lines should build a 2x2 matrix, fill it, and print its transpose. Put them in the right order:
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.
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) .
🔎 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.
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
2. For two Eigen matrices, what does a * b compute?
The matrix product — not element-wise. Use a.array() * b.array() for element-wise.
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)
Frequently Asked Questions
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.
🎉 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 and any (C++17)