Solutions¶
Basic Matrix and Vector operations¶
1. Vector Creation and Access
#include <iostream>
#include <Eigen/Dense>
#include <print>
#include "utils_print.h"
int main()
{
using Eigen::RowVector;
using Eigen::VectorXi;
RowVector<double, 5> v1{1.0, 2.0, 3.0, 4.0, 5.0};
VectorXi v2{{1, 2, 3, 4, 5}};
utils::print("v1", v1);
utils::print("v2", v2);
std::printf("v1[0] = %.1f\n", v1[0]);
std::printf("v2[0] = %d\n", v2[0]);
}
Open solution in Compiler Explorer
2. Matrix Initialization
#include <iostream>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix3d;
using Eigen::Matrix;
using std::cout;
Matrix3d A;
A.setZero();
// A = Matrix3d::Zero();
utils::print("A", A);
Matrix<double, 2, 4> B;
B << 1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0;
utils::print("B", B);
}
Open solution in Compiler Explorer
3. Basic Math Functions
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::RowVector;
// -5 -4 -3 -2 -1 0 1 2 3 4 5
RowVector<double, 11> v1;
v1.setLinSpaced(11, -5.0, 5.0);
// v1 = Vector<double, 11>::LinSpaced(11, -5.0, 5.0);
utils::print("v1", v1);
auto v2 = v1.cwiseAbs().cwiseSqrt();
auto v2a = v1.array().abs().sqrt().matrix();
utils::print("v2", v2);
utils::print("v2a", v2a);
auto v3 = v1;
for (auto i = 0; i < v3.size(); ++i)
v3[i] = exp(v3[i]);
utils::print("v3", v3);
std::println("v1.sum() = {}", v1.sum());
std::println("v1.prod() = {}", v1.prod());
std::println("v1.mean() = {}", v1.mean());
std::println("v1.maxCoeff() = {}", v1.maxCoeff());
std::println("v1.minCoeff() = {}", v1.minCoeff());
}
https://godbolt.org/z/Kzh94ME6o
4. Coefficient-wise Operations
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::RowVector;
using std::cout;
RowVector<double, 10> v1;
v1.setRandom();
utils::print("v1", v1);
RowVector<double, 10> v2;
v2.setRandom();
utils::print("v2", v2);
utils::print("v1 + v2", v1 + v2);
utils::print("v1 - v2", v1 - v2);
utils::print("v1.cwiseProduct(v2)", v1.cwiseProduct(v2));
std::println("v1.dot(v2) = {}", v1.dot(v2));
}
https://godbolt.org/z/dv7e6ffxr
5. Matrix Operations
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix3d;
using std::cout;
Matrix3d A;
A.setRandom();
utils::print("A", A);
Matrix3d B;
B.setRandom();
utils::print("B", B);
utils::print("A + B", A + B);
utils::print("A - B", A - B);
utils::print("A.array() * B.array()", A.array() * B.array());
utils::print("A * B", A * B);
}
https://godbolt.org/z/WxWMPjxc5
6. Vector-Matrix Operations
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix3d;
using Eigen::Vector3d;
using std::cout;
Matrix3d A;
A.setRandom();
utils::print("A", A);
Vector3d b; // ColumnVector [3 x 1]
b.setRandom();
utils::print("b", b);
utils::print("A * b", A * b);
}
Open solution in Compiler Explorer
7. Special Matrix Operations
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix4d;
using Eigen::Matrix3d;
using Eigen::MatrixXd;
using Eigen::FullPivLU;
using std::cout;
Matrix4d A;
A.setRandom();
utils::print("A", A);
std::println("det(A) = {}", A.determinant());
utils::print("A^(-1)", A.inverse());
utils::print("A^T", A.transpose());
utils::print("A * A^(-1)", A * A.inverse());
if ((A * A.inverse()).isIdentity())
std::println("A * A^(-1) is identity");
else
std::println("A * A^(-1) is not identity");
Matrix3d B;
B << 1, 2, 3, 4, 5, 6, 7, 8, 9;
auto det = B.determinant();
bool isSingular = std::abs(det) < 1e-10;
if (isSingular)
std::println("B is singular");
else
std::println("B is not singular");
FullPivLU<MatrixXd> lu(B);
bool isSingular_lu = !lu.isInvertible();
if (isSingular_lu)
std::println("B is singular (LU)");
else
std::println("B is not singular (LU)");
}
Open solution in Compiler Explorer
Advanced Matrix operations¶
8. Block Operations
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix4d;
using Eigen::MatrixXd;
using Eigen::Matrix2d;
Matrix4d A;
A << 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16;
utils::print("A = ", A);
MatrixXd B = A.block(0, 0, 2, 2);
utils::print("B = ", B);
MatrixXd C = A.block(2, 2, 2, 2);
utils::print("C = ", C);
Matrix2d D;
D << 42, 42,
42, 42;
utils::print("D = ", D);
A.block(2, 2, 2, 2) = D;
utils::print("A = ", A);
}
Open solution in Compiler Explorer
9. Row and Column Operations
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix;
using Eigen::VectorXd;
using std::cout;
Matrix<double, 3, 4> A;
A.setRandom();
utils::print("A", A);
utils::print("A.row(1)", A.row(1));
utils::print("A.col(2)", A.col(2));
A.row(1) << 1, 2, 3, 4;
utils::print("A", A);
VectorXd temp = A.col(2);
A.col(2) = A.col(3);
A.col(3) = temp;
utils::print("A", A);
A.col(2).swap(A.col(3));
utils::print("A", A);
}
Open solution in Compiler Explorer
10. Resizing and Reshaping
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix;
using Eigen::Vector;
Matrix<double, 2, 3> A;
A << 1, 2,
3, 4,
5, 6;
utils::print("A", A);
Matrix<double, 3, 2> B = A.reshaped(3, 2);
utils::print("B", B);
Vector<double, 6> v;
v << 1, 2, 3, 4, 5, 6;
utils::print("v", v);
Matrix<double, 2, 3> C = v.reshaped(2, 3);
utils::print("C", C);
}
Open solution in Compiler Explorer
11. Concatenation
#include <iostream>
#include <cmath>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix2d;
using Eigen::MatrixXd;
Matrix2d A;
A << 1, 2,
3, 4;
utils::print("A", A);
Matrix2d B;
B << 5, 6,
7, 8;
utils::print("B", B);
MatrixXd C(A.rows(), A.cols() + B.cols());
C << A, B;
utils::print("C", C);
MatrixXd D(A.rows() + B.rows(), A.cols());
D << A, B;
utils::print("D", D);
}
Open solution in Compiler Explorer
12. Advanced Slicing
#include <iostream>
#include <cmath>
#include <vector>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix;
using Eigen::Matrix2d;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::Index;
Matrix<double, 5, 5> A;
A << 1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
16, 17, 18, 19, 20,
21, 22, 23, 24, 25;
utils::print("A", A);
std::vector<Index> rows = {1, 3, 4};
std::vector<Index> cols = {0, 2};
MatrixXd B = A(rows, cols);
utils::print("B", B);
utils::print("diagonal of A", A.diagonal());
auto n = A.rows();
VectorXd antiDiagonal(n);
for (int i = 0; i < n; i++)
antiDiagonal(i) = A(i, n - i - 1);
utils::print("anti-diagonal of A", antiDiagonal);
auto tiledRows = 4;
auto tiledCols = 3;
Matrix2d C;
C << 1, 2, 3, 4;
MatrixXd D(tiledRows * C.rows(), tiledCols * C.cols());
for (auto i = 0; i < tiledRows; i++)
for (auto j = 0; j < tiledCols; j++)
D.block(i * C.rows(), j * C.cols(), C.rows(), C.cols()) = C;
utils::print("D", D);
// Demonstrate different formatting options
std::print("--- Different Format Examples ---\n\n");
Matrix2d E;
E << 1.23456789, 2.3456789,
3.456789, 4.56789;
utils::print("E (Default)", E);
utils::print("E (Compact)", E, PrintFormat::Compact);
utils::print("E (Python)", E, PrintFormat::Python);
utils::print("E (Clean)", E, PrintFormat::Clean);
utils::print("E (Octave)", E, PrintFormat::Octave);
utils::print("E (CSV)", E, PrintFormat::CSV);
// Custom format with specific precision
Eigen::IOFormat CustomFmt(2, 0, ", ", "\n", "[", "]");
utils::print("E (Custom 2 decimals)", E, CustomFmt);
}
Open solution in Compiler Explorer
13. Linear Algebra Operations
#include <iostream>
#include <cmath>
#include <vector>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::MatrixXd;
using Eigen::VectorXd;
MatrixXd A(10, 10);
A << MatrixXd::Random(10, 10);
utils::print("A", A);
VectorXd b(10);
b << VectorXd::Random(10);
utils::print("b", b);
VectorXd x = A.fullPivLu().solve(b);
utils::print("The solution is:", x);
std::println("The relative error is: {}", (A * x - b).norm() / b.norm());
std::println("A * x = {}", A * x);
}
Open solution in Compiler Explorer
14. Eigenvalues and Eigenvectors
#include <iostream>
#include <cmath>
#include <vector>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
int main()
{
using Eigen::Matrix3d;
using Eigen::SelfAdjointEigenSolver;
Matrix3d A;
A << 1, 2, 7,
2, 5, 6,
7, 6, 10;
utils::print("A", A);
SelfAdjointEigenSolver<Eigen::Matrix3d> es(A);
if (es.info() != Eigen::Success)
{
std::println("Eigen solver failed.");
return 1;
}
utils::print("The eigenvalues of A are:", es.eigenvalues());
utils::print("The matrix of eigenvectors, V, is:", es.eigenvectors());
auto v1 = es.eigenvectors().col(0);
auto v2 = es.eigenvectors().col(1);
auto v3 = es.eigenvectors().col(2);
auto lambda1 = es.eigenvalues()(0);
auto lambda2 = es.eigenvalues()(1);
auto lambda3 = es.eigenvalues()(2);
utils::print("The first eigenvector is:", v1);
utils::print("The second eigenvector is:", v2);
utils::print("The third eigenvector is:", v3);
std::println();
std::println("The first eigenvalue is: {}", lambda1);
std::println("The second eigenvalue is: {}", lambda2);
std::println("The third eigenvalue is: {}\n", lambda3);
Matrix3d I = Matrix3d::Identity();
std::println("(A-lambda1 * I) * v1 = {}", (A - lambda1 * I) * v1);
std::println("(A-lambda2 * I) * v2 = {}", (A - lambda2 * I) * v2);
std::println("(A-lambda3 * I) * v3 = {}", (A - lambda3 * I) * v3);
}
Open solution in Compiler Explorer
Practical Applications¶
15. Image Processing Basics
#include <cmath>
#include <vector>
#include <numbers>
#include <print>
#include <Eigen/Dense>
#include "utils_print.h"
#include <img/Image.h>
Eigen::MatrixXd adjustBrightnessContrast(const Eigen::MatrixXd &image, double alpha, double beta)
{
// Convert to array for element-wise operations
Eigen::ArrayXXd result = image.array();
// Apply contrast (multiply)
result = alpha * result;
// Apply brightness (add)
result = result + beta;
// Clamp values to valid pixel range [0, 1]
result = result.max(0.0).min(1.0);
return result.matrix();
}
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;
double 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;
}
Eigen::MatrixXd applyGaussianFilter(const Eigen::MatrixXd &image, int kernelSize, double sigma)
{
Eigen::MatrixXd result = image;
Eigen::MatrixXd kernel = createGaussianKernel(kernelSize, sigma);
int kernelRadius = kernelSize / 2;
for (int y = kernelRadius; y < image.rows() - kernelRadius; y++)
{
for (int x = kernelRadius; x < image.cols() - kernelRadius; x++)
{
double sum = 0.0;
for (int ky = 0; ky < kernelSize; ky++)
{
for (int kx = 0; kx < kernelSize; kx++)
{
int imgX = x + kx - kernelRadius;
int imgY = y + ky - kernelRadius;
sum += image(imgY, imgX) * kernel(ky, kx);
}
}
result(y, x) = sum;
}
}
return result;
}
img::ImageGd copyToImage(const Eigen::MatrixXd &mat)
{
img::ImageGd image;
const int rows = static_cast<int>(mat.rows());
const int cols = static_cast<int>(mat.cols());
image.resize(rows, cols);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
image(i, j) = mat(i, j);
return image;
}
int main()
{
using std::cout;
using Eigen::MatrixXd;
using img::ImageGd;
ImageGd image;
std::println("Loading image...");
if (!load("images/half-moon-986269.png", image))
{
std::println("Error loading image");
return 1;
}
// Create a matrix with the image data
auto mat = image.as_matrix();
std::println("Adjusting brightness contrast...");
MatrixXd brighterImageMat = adjustBrightnessContrast(mat, 1.0, 0.5);
// Create a new image with the modified data
std::println("Converting to image...");
auto brighterImage = copyToImage(brighterImageMat);
// Save the new image
std::println("Saving image...");
if (!save("images/brighter-half-moon-986269.png", brighterImage))
{
std::println("Error saving image");
return 1;
}
std::println("Applying Gaussian filter...");
MatrixXd blurredImageMat = applyGaussianFilter(mat, 10, 1.0);
// Create a new image with the modified data
std::println("Converting to image...");
auto blurredImage = copyToImage(blurredImageMat);
// Save the new image
std::println("Saving image...");
if (!save("images/blurred-half-moon-986269.png", blurredImage))
{
std::println("Error saving image");
return 1;
}
}