Exercises¶
Use the button below to open a template in Compiler Explorer with the Eigen library included. You can use this template to complete the exercises below.
- Open solution template in Compiler explorer
- Solutions
- Use the template folder for local development
How to use this guide¶
In a 6-hour course, we recommend:
- Lab sessions 1–2 (10:20–11:00, 13:00–13:40): Exercises 1–7 (Basic & Intermediate)
- Lab session 3 (14:20–15:00): Exercises 8–12 (Advanced operations) or continue with 1–7 if needed
- Self-study / extended practice: Exercises 13–15 (Linear algebra & applications)
Prerequisites: Complete exercises 1–3 before moving to exercises 4–7. Complete 1–7 before attempting 8–15.
Difficulty legend: 🟢 Beginner | 🟡 Intermediate | 🔴 Advanced
Basic Matrix and Vector Operations¶
1. Vector Creation and Access¶
🟢 Beginner | ⏱️ 5 min
- Create a 5-element vector using Eigen and initialize it with values 1 through 5.
- Print the vector's elements and demonstrate how to access individual elements.
2. Matrix Initialization¶
🟢 Beginner | ⏱️ 5 min
- Create a 3x3 matrix with all elements set to zero.
- Initialize a 2x4 matrix with specific values of your choice.
- Print both matrices to verify their contents.
3. Basic Math Functions¶
🟢 Beginner | ⏱️ 10 min
- Create a vector with values ranging from -5 to 5.
- Apply the absolute value, square root (for positive elements), and exponential functions.
- Calculate the sum, mean, minimum, and maximum values of the vector.
Tip
If you want to apply sqrt to all components in a vector you have to use the .cwiseSqrt() method. The same applies to other functions like .cwiseAbs() and .cwiseExp(). If you want to apply a function to all values in a matrix, you can use the .array() method to convert the matrix to an array and then apply the function. A.array().sqrt() will apply the square root to all elements in the matrix.
It is also possible to use the .unaryExpr() method to apply a function to all elements in a matrix. For example, A.unaryExpr([](double x) { return foo(x); }); will apply the function foo() to all elements in the matrix A.
4. Coefficient-wise Operations¶
🟡 Intermediate | ⏱️ 10 min
- Create two vectors of the same length.
- Perform element-wise multiplication, division, and power operations.
- Calculate the dot product and compare with element-wise multiplication.
5. Matrix Operations¶
🟡 Intermediate | ⏱️ 10 min
- Create two 3x3 matrices with different values.
- Perform and print the results of addition, subtraction, and element-wise multiplication.
- Calculate and print the matrix product of the two matrices.
6. Vector-Matrix Operations¶
🟡 Intermediate | ⏱️ 10 min
- Create a 3x3 matrix and a 3-element vector.
- Multiply the matrix by the vector and explain the result.
- Experiment with different ways to perform the multiplication.
7. Special Matrix Operations¶
🟡 Intermediate | ⏱️ 15 min
- Create a 4x4 matrix and calculate its determinant, inverse, and transpose.
- Verify that
A * A^-1equals the identity matrix (within numerical precision). - Explore how to check if a matrix is singular and handle potential errors.
Tip
In addition to using the .determinant() to determine if a matrix is singular it is also possible to use the .fullPivLu().isInvertible() method. This method returns a boolean value indicating if the matrix is invertible. The .fullPivLu() method can also be used to calculate the inverse of a matrix.
Advanced Matrix Operations¶
8. Block Operations¶
🟡 Intermediate | ⏱️ 15 min
- Create a 4x4 matrix with sequential numbers (1-16).
- Extract the 2x2 block in the top-left corner.
- Extract the 2x2 block in the bottom-right corner.
- Replace the bottom-left 2x2 block with a new 2x2 matrix.
Tip
The .block() method can be used to extract a block from a matrix. The method takes four arguments: the row and column index of the top-left corner of the block, and the number of rows and columns in the block. For example, A.block(0, 0, 2, 2) will extract a 2x2 block from the top-left corner of the matrix A. It is also possible to assign a matrix using the .block() method. A.block(0, 0, 2, 2) = B; will replace the top-left 2x2 block in A with the matrix B.
9. Row and Column Operations¶
🟡 Intermediate | ⏱️ 15 min
- Create a 3x4 matrix with random values.
- Extract the second row and third column.
- Replace the first row with new values.
- Swap two columns of your choice.
Tip
The .swap() method can be used to swap two columns in a matrix.
10. Resizing and Reshaping¶
🟡 Intermediate | ⏱️ 10 min
- Create a 2x3 matrix and then resize it to a 3x2 matrix.
- Create a 6-element vector and reshape it into a 2x3 matrix.
- Discuss what happens to the elements during these operations.
Tip
Use the .reshaped() method to reshape a matrix.
11. Concatenation¶
🟡 Intermediate | ⏱️ 15 min
- Create two 2x2 matrices.
- Horizontally concatenate them to form a 2x4 matrix.
- Vertically concatenate them to form a 4x2 matrix.
- Create and demonstrate a function that can concatenate matrices of compatible dimensions.
Tip
The << operator can be used to concatenate matrices. A << B, C; will concatenate the matrices B and C horizontally or vertically depending on the matrix shapes.
12. Advanced Slicing¶
🔴 Advanced | ⏱️ 20 min
- Create a 5x5 matrix with sequential values.
- Extract non-contiguous rows and columns (for example rows 1, 3, 4 and columns 0, 2).
- Extract a diagonal or anti-diagonal of the matrix.
- Create a tiled pattern by repeating a smaller matrix.
Tip
std::vector<int> indices = {1, 3, 4}; can be used as indices to extract non-contiguous areas of a matrix.
13. Linear Algebra Operations¶
🔴 Advanced | ⏱️ 20 min
- Create a system of linear equations represented as
Ax = b. - Solve the system using Eigen's solver capabilities.
- Verify your solution by substituting it back into the original equations.
Tip
Use .fullPivLu() to solve a system of linear equations.
14. Eigenvalues and Eigenvectors¶
🔴 Advanced | ⏱️ 20 min
- Create a symmetric 3x3 matrix.
- Calculate its eigenvalues and eigenvectors.
- Verify that
A v = lambda vfor each eigenvalue-eigenvector pair.
Tip
Use the class SelfAdjointEigenSolver<Eigen::Matrix3d> es(A); to compute eigenvalues and eigenvectors. Use the es.eigenvalues() and es.eigenvectors() methods to calculate the eigenvalues and eigenvectors of a matrix.
Practical Applications¶
15. Image Processing Basics¶
🔴 Advanced | ⏱️ 30 min
- Represent a grayscale image as an Eigen matrix.
- Implement basic operations like brightness adjustment and contrast enhancement.
- Apply simple filters (for example blur) using matrix operations.
Tip
Use the Img library to load images that can be converted to Eigen matrices. The library can be found here:
An image can be loaded and converted to a grayscale image (range [0.0..1.0]) using the following code snippet:
Img::ImageGd image;
std::cout << "Loading image..." << std::endl;
if (!Img::load("images/half-moon-986269.png", image))
{
std::cout << "Error loading image" << std::endl;
return 1;
}
Conversion from an Image class to an Eigen matrix can be done using the .as_matrix() method.
Converting back to an Image class can be done using the following function:
Img::ImageGd copyToImage(const Eigen::MatrixXd &mat)
{
ImageGd image;
image.resize(mat.rows(), mat.cols());
for (int i = 0; i < mat.rows(); i++)
for (int j = 0; j < mat.cols(); j++)
image(i, j) = mat(i, j);
return image;
}
Saving the image to a file can be done using the following code snippet:
if (!Img::save("output.png", copyToImage(matrix)))
{
std::cout << "Error saving image" << std::endl;
return 1;
}
The gaussian kernel can be generated using the following function:
Eigen::MatrixXd createGaussianKernel(int size, double sigma)
{
if (size % 2 == 0)
{
size++; // Make sure kernel size is odd
}
Eigen::MatrixXd kernel(size, size);
int center = size / 2;
double sum = 0.0;
// Fill the kernel with Gaussian values
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
int dx = x - center;
int dy = y - center;
float exponent = -(dx * dx + dy * dy) / (2 * sigma * sigma);
kernel(y, x) = std::exp(exponent) / (2 * std::numbers::pi * sigma * sigma);
sum += kernel(y, x);
}
}
// Normalize the kernel so its sum equals 1
kernel /= sum;
return kernel;
}