Eigen для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Eigen для C++: полное руководство с примерами

1. Что это и зачем нужна

Eigen — это высокопроизводительная, шаблонная библиотека линейной алгебры для языка C++. Она предоставляет разработчикам мощные и удобные инструменты для работы с матрицами, векторами, численными решателями и связанными алгоритмами. В отличие от многих других библиотек (например, BLAS/LAPACK), Eigen написан на чистом C++ без внешних зависимостей, что делает его идеальным выбором для проектов, где важна простота интеграции и переносимость кода.

Зачем она нужна? В современном мире программирования линейная алгебра лежит в основе огромного количества задач: от компьютерной графики и обработки изображений до машинного обучения, робототехники и научных симуляций. Eigen позволяет разработчикам не изобретать велосипед, а использовать проверенные, оптимизированные алгоритмы, которые часто работают быстрее, чем написанные вручную реализации. Библиотека активно использует шаблоны C++ (template expressions) для выполнения сложных оптимизаций на этапе компиляции, что позволяет избежать накладных расходов на создание временных объектов и объединять операции в один эффективный цикл.

Eigen поддерживает все основные типы матриц (плотные, разреженные, фиксированного и динамического размера), широкий спектр разложений (LU, QR, SVD, Cholesky, собственные значения) и геометрические преобразования (повороты, трансляции, аффинные преобразования). Благодаря своей гибкости и производительности, Eigen является стандартом де-факто для многих C++ проектов, включая такие известные фреймворки, как ROS (Robot Operating System), TensorFlow (частично) и CGAL.

2. Установка

Eigen — это библиотека только с заголовочными файлами (header-only). Это означает, что вам не нужно компилировать отдельную библиотеку или линковаться с ней. Достаточно скачать файлы и указать компилятору путь к ним.

Способ 1: Ручная установка (рекомендуемый для изучения)

# Скачиваем последнюю версию с официального сайта или GitHub
wget https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz
tar -xzf eigen-3.4.0.tar.gz
sudo mv eigen-3.4.0 /usr/local/include/eigen3

Теперь при компиляции нужно указать путь к заголовочным файлам:

g++ -std=c++11 -I /usr/local/include/eigen3 my_program.cpp -o my_program

Способ 2: Через пакетный менеджер (Linux/macOS)

# Ubuntu/Debian
sudo apt-get install libeigen3-dev

# macOS (через Homebrew)
brew install eigen

Способ 3: Через vcpkg или Conan (Windows)

# vcpkg
vcpkg install eigen3

# Conan
conan install eigen/3.4.0@

Важно: В отличие от Python (pip) или JavaScript (npm), Eigen не устанавливается через пакетный менеджер языка. Это системная библиотека на C++.

3. Быстрый старт — минимальный рабочий пример

Создайте файл main.cpp и скопируйте туда следующий код:

#include <iostream>
#include <Eigen/Dense>  // Основной заголовок для плотных матриц

int main() {
    // Создаем матрицу 2x2 и заполняем её
    Eigen::Matrix2d mat;
    mat << 1, 2,
           3, 4;

    // Создаем вектор 2x1
    Eigen::Vector2d vec(5, 6);

    // Умножаем матрицу на вектор
    Eigen::Vector2d result = mat * vec;

    // Выводим результат
    std::cout << "Matrix:\n" << mat << std::endl;
    std::cout << "Vector:\n" << vec << std::endl;
    std::cout << "Result (mat * vec):\n" << result << std::endl;

    return 0;
}

Компиляция и запуск:

g++ -std=c++11 -I /path/to/eigen main.cpp -o main
./main

Вывод:

Matrix:
1 2
3 4
Vector:
5
6
Result (mat * vec):
17
39

4. Основные методы/функции/классы

4.1. Eigen::MatrixXd — Матрица динамического размера

Сигнатура: class MatrixXd;

Что делает: Создает матрицу, размер которой задается во время выполнения. X означает динамический размер, d — тип double.

#include <Eigen/Dense>
#include <iostream>

int main() {
    Eigen::MatrixXd m(2, 3); // 2 строки, 3 столбца
    m(0, 0) = 1.0;
    m(1, 2) = 5.5;
    std::cout << "MatrixXd:\n" << m << std::endl;
    return 0;
}

4.2. .rows() и .cols() — Получение размеров

Сигнатура: Index rows() const; и Index cols() const;

Что делает: Возвращает количество строк и столбцов матрицы соответственно.

Eigen::MatrixXd m(4, 7);
std::cout << "Rows: " << m.rows() << ", Cols: " << m.cols() << std::endl;
// Вывод: Rows: 4, Cols: 7

4.3. .transpose() — Транспонирование

Сигнатура: TransposeReturnType transpose();

Что делает: Возвращает транспонированную матрицу. Важно: a = a.transpose() вызовет ошибку (aliasing issue). Используйте .transposeInPlace().

Eigen::Matrix2i a;
a << 1, 2,
     3, 4;
Eigen::Matrix2i b = a.transpose();
std::cout << "Original:\n" << a << "\nTransposed:\n" << b << std::endl;

4.4. .inverse() — Обратная матрица

Сигнатура: InverseReturnType inverse() const;

Что делает: Вычисляет обратную матрицу. Для больших матриц рекомендуется использовать разложения (например, .partialPivLu().solve()).

Eigen::Matrix2d a;
a << 4, 7,
     2, 6;
Eigen::Matrix2d inv_a = a.inverse();
std::cout << "Inverse:\n" << inv_a << std::endl;
// Проверка: a * inv_a должно быть единичной матрицей
std::cout << "Check (should be identity):\n" << a * inv_a << std::endl;

4.5. .determinant() — Детерминант

Сигнатура: Scalar determinant() const;

Что делает: Вычисляет определитель квадратной матрицы.

Eigen::Matrix3d a;
a << 1, 2, 3,
     4, 5, 6,
     7, 8, 10; // Матрица с детерминантом -3
std::cout << "Determinant: " << a.determinant() << std::endl;
// Вывод: Determinant: -3

4.6. .eigenvalues() — Собственные значения

Сигнатура: EigenSolver<MatrixType>::EigenvalueType eigenvalues() const;

Что делает: Вычисляет собственные значения матрицы. Возвращает комплексный вектор.

Eigen::Matrix2d a;
a << 2, 1,
     1, 2;
Eigen::EigenSolver<Eigen::Matrix2d> solver(a);
std::cout << "Eigenvalues:\n" << solver.eigenvalues() << std::endl;
// Вывод: (3, 0) и (1, 0)

4.7. .block() — Извлечение подматрицы (блока)

Сигнатура: Block<Derived> block(Index startRow, Index startCol, Index blockRows, Index blockCols);

Что делает: Позволяет получить доступ к подматрице (блоку) исходной матрицы. Изменения в блоке влияют на исходную матрицу.

Eigen::Matrix4d m = Eigen::Matrix4d::Random();
std::cout << "Top-left 2x2 block:\n" << m.block<2,2>(0,0) << std::endl;

// Изменяем блок
m.block<2,2>(2,2) = Eigen::Matrix2d::Zero();
std::cout << "Matrix after zeroing bottom-right block:\n" << m << std::endl;

4.8. .col() и .row() — Доступ к строкам и столбцам

Сигнатура: ColXpr col(Index i); и RowXpr row(Index i);

Что делает: Возвращает ссылку на i-й столбец или i-ю строку матрицы.

Eigen::Matrix3d m = Eigen::Matrix3d::Identity();
m.col(1) = Eigen::Vector3d(10, 20, 30); // Заменяем второй столбец
std::cout << "Modified matrix:\n" << m << std::endl;

4.9. .norm() — Норма вектора

Сигнатура: Scalar norm() const;

Что делает: Вычисляет L2 норму (длину) вектора. Для матриц возвращает норму Фробениуса.

Eigen::Vector3d v(3.0, 4.0, 0.0);
std::cout << "Norm of (3,4,0): " << v.norm() << std::endl;
// Вывод: 5

4.10. .solve() — Решение системы линейных уравнений

Сигнатура: Solve<Decomposition> solve(const MatrixBase<OtherDerived> &b) const;

Что делает: Решает систему Ax = b. Обычно используется с разложением (например, ldlt, partialPivLu).

Eigen::Matrix2d A;
A << 2, 1,
     1, 3;
Eigen::Vector2d b(4, 5);

Eigen::Vector2d x = A.ldlt().solve(b);
std::cout << "Solution x:\n" << x << std::endl;
// Проверка: A * x должно быть равно b
std::cout << "Check (A*x):\n" << A * x << std::endl;

5. Реальный практический пример: Аппроксимация кривой методом наименьших квадратов

В этом примере мы решим задачу подгонки полинома второй степени под набор точек данных. Это классическая задача линейной регрессии, решаемая с помощью псевдообратной матрицы (SVD).

#include <iostream>
#include <vector>
#include <Eigen/D                    

Рекомендаций