Bamba news

C++ Eigenライブラリ入門:行列・ベクトル計算を高速かつ直感的に

Eigenは、C++で高度な線形代数計算を可能にする強力なテンプレートライブラリです。この記事では、Eigenの基本的な使い方から、行列やベクトルの操作、連立一次方程式の解法、さらには応用例まで、初心者にも分かりやすく丁寧に解説します。ロボティクス、3Dグラフィックス、機械学習などの分野で必須となる行列計算を、Eigenで効率的に行いましょう。

Tags:#開発

Eigenとは何か?

Eigenは、C++のための高機能な線形代数ライブラリです。線形代数とは、ベクトルや行列などを扱う数学の分野で、科学技術計算、3Dグラフィックス、ロボティクス、機械学習など、現代のプログラミングにおいて非常に重要な役割を果たします。

Eigenの最大の特徴は、ヘッダファイルのみで構成されている点です。これは、ライブラリを別途ビルド(コンパイルして実行可能な形式にすること)する必要がなく、自分のプロジェクトにヘッダファイルをインクルードするだけで、すぐに強力な行列・ベクトル計算機能を利用できることを意味します。

C++のテンプレートという機能を駆使して設計されており、これにより非常に高速な計算性能と、数学の数式を書くのに近い直感的なAPI(プログラムの命令の仕方)を両立しています。

なぜEigenを使うのか? そのメリット

多くの開発者がEigenを選ぶのには、明確な理由があります。

  • 圧倒的なパフォーマンス: Eigenは「Expression Templates」という先進的なC++のテクニックを利用しています。これにより、コンパイル時に計算式が最適化され、一時的なオブジェクトの生成を最小限に抑えます。結果として、手で最適化したCコードや、他の多くのライブラリに匹敵、あるいはそれを凌駕するほどの高速な実行速度を実現します。
  • 簡単な導入: 前述の通り、ヘッダファイルをインクルードするだけです。複雑なインストール作業やビルド設定は不要で、プロジェクトに手軽に組み込めます。
  • 直感的で美しいAPI: Eigenのコードは、数学の数式に非常に近い形で記述できます。例えば、c = a + b のように、ベクトルや行列の和を自然に表現できます。これにより、コードの可読性が高まり、バグの少ない、メンテナンスしやすいプログラムを書くことができます。
  • 豊富な機能: 固定サイズの小さな行列から、実行時にサイズが決まる大きな行列、さらには成分のほとんどがゼロである「疎行列」まで、幅広い種類の行列を扱えます。基本的な四則演算はもちろん、転置、逆行列、行列式、固有値分解、特異値分解(SVD)、LU分解、QR分解といった、高度な線形代数の演算が豊富に用意されています。
  • 柔軟なライセンス: EigenはMozilla Public License 2.0 (MPL2)というライセンスで提供されています。これは、個人利用・商用利用を問わず、オープンソースではない独自のソフトウェアにも組み込んで利用できることを意味します。

Eigenの基本的な使い方

Eigenを使い始めるのは非常に簡単です。ここでは、基本的な行列とベクトルの作成方法から解説します。

準備:ヘッダのインクルード

Eigenの主要な機能を使うには、<Eigen/Dense>ヘッダをインクルードします。このヘッダが、密行列(要素がほぼ非ゼロの行列)に関連するクラスや関数をまとめて取り込んでくれます。

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

int main() {
    // ここにEigenのコードを記述していきます
}
-```

### 行列 (Matrix) の宣言と初期化

Eigenでは、`Eigen::Matrix`クラスを使って行列を表現します。テンプレート引数で、要素の型、行数、列数を指定します。

例えば、`double`型で3行3列の行列を宣言するには、以下のように書きます。

```cpp
// double型で3行3列の行列を宣言
Eigen::Matrix<double, 3, 3> m1;

より一般的に、よく使われる型には便利な型エイリアスが用意されています。

  • MatrixXd: Matrix<double, Dynamic, Dynamic> (double型、動的サイズ)
  • MatrixXf: Matrix<float, Dynamic, Dynamic> (float型、動お的サイズ)
  • Matrix3d: Matrix<double, 3, 3> (double型、3x3の固定サイズ)
  • Matrix4f: Matrix<float, 4, 4> (float型、4x4の固定サイズ)

動的サイズ(Dynamic)の行列は、実行時にサイズを指定できます。

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

int main() {
    // 3x3のdouble型行列 (固定サイズ)
    Eigen::Matrix3d m_fixed;

    // << 演算子を使って値を設定 (行優先で流し込む)
    m_fixed << 1, 2, 3,
               4, 5, 6,
               7, 8, 9;

    std::cout << "m_fixed:\n" << m_fixed << std::endl;

    // 2x4のfloat型行列 (動的サイズ)
    // コンストラクタで行と列のサイズを指定
    Eigen::MatrixXf m_dynamic(2, 4);
    m_dynamic << 1.1, 1.2, 1.3, 1.4,
                 2.1, 2.2, 2.3, 2.4;
    
    std::cout << "\nm_dynamic:\n" << m_dynamic << std::endl;

    // 特別な行列の生成
    Eigen::MatrixXd I = Eigen::MatrixXd::Identity(3, 3); // 3x3の単位行列
    Eigen::MatrixXd Z = Eigen::MatrixXd::Zero(2, 3);     // 2x3のゼロ行列
    Eigen::MatrixXd R = Eigen::MatrixXd::Random(3, 3);   // -1から1の範囲の乱数で初期化

    std::cout << "\nIdentity matrix:\n" << I << std::endl;
    std::cout << "\nZero matrix:\n" << Z << std::endl;
    std::cout << "\nRandom matrix:\n" << R << std::endl;
}

ベクトル (Vector) の宣言と初期化

ベクトルは、1列の行列と考えることができます。Eigenでもそのように扱われ、行列と同様に宣言できます。

よく使われるベクトルの型エイリアスには以下のようなものがあります。

  • VectorXd: Matrix<double, Dynamic, 1> (double型、動的サイズの列ベクトル)
  • VectorXf: Matrix<float, Dynamic, 1> (float型、動的サイズの列ベクトル)
  • Vector3d: Matrix<double, 3, 1> (double型、3次元の固定サイズ列ベクトル)
  • Vector2f: Matrix<float, 2, 1> (float型、2次元の固定サイズ列ベクトル)

行ベクトルを使いたい場合は RowVector を使います。

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

int main() {
    // 3次元のdouble型列ベクトル (固定サイズ)
    Eigen::Vector3d v1(1.0, 2.0, 3.0);
    std::cout << "v1:\n" << v1 << std::endl;

    // 4次元のfloat型列ベクトル (動的サイズ)
    Eigen::VectorXf v2(4);
    v2 << 4.5f, 5.5f, 6.5f, 7.5f;
    std::cout << "\nv2:\n" << v2 << std::endl;

    // 行ベクトルの場合
    Eigen::RowVector3d rv1(1, 2, 3);
    std::cout << "\nRow vector rv1:\n" << rv1 << std::endl;
}

行列とベクトルの基本的な演算

Eigenの真価は、これらのオブジェクトを使った演算が非常に直感的に行える点にあります。

四則演算

行列・ベクトルの加算、減算、スカラ倍、スカラ除算は、+, -, *, / 演算子を使ってそのまま記述できます。

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

int main() {
    Eigen::Matrix2d A;
    A << 1, 2,
         3, 4;

    Eigen::Matrix2d B;
    B << 5, 6,
         7, 8;

    Eigen::Vector2d v(9, 10);
    
    // 行列の加算
    Eigen::Matrix2d C = A + B;
    std::cout << "A + B =\n" << C << std::endl;

    // 行列の減算
    Eigen::Matrix2d D = A - B;
    std::cout << "\nA - B =\n" << D << std::endl;

    // 行列のスカラ倍
    Eigen::Matrix2d E = A * 2.5;
    std::cout << "\nA * 2.5 =\n" << E << std::endl;

    // 行列とベクトルの積
    Eigen::Vector2d w = A * v;
    std::cout << "\nA * v =\n" << w << std::endl;

    // 行列同士の積
    Eigen::Matrix2d F = A * B;
    std::cout << "\nA * B =\n" << F << std::endl;
}

転置、逆行列、行列式

線形代数で頻繁に登場する操作も、簡単なメソッド呼び出しで実現できます。

  • 転置 (Transpose): .transpose()
  • 逆行列 (Inverse): .inverse()
  • 行列式 (Determinant): .determinant()
#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Matrix3d m;
    m << 1, 2, 1,
         2, 1, 0,
        -1, 1, 2;

    std::cout << "Original matrix m:\n" << m << std::endl;

    // 転置行列
    std::cout << "\nTranspose of m:\n" << m.transpose() << std::endl;

    // 逆行列
    std::cout << "\nInverse of m:\n" << m.inverse() << std::endl;

    // 行列式
    std::cout << "\nDeterminant of m: " << m.determinant() << std::endl;
    
    // 検算: m * m.inverse() は単位行列になるはず
    Eigen::Matrix3d I = m * m.inverse();
    std::cout << "\nm * m.inverse():\n" << I << std::endl;
}

ベクトル演算

ベクトルの内積や外積も簡単に計算できます。

  • 内積 (Dot Product): .dot() または v1.transpose() * v2
  • 外積 (Cross Product): .cross() (3次元ベクトルのみ)
#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Vector3d v1(1, 2, 3);
    Eigen::Vector3d v2(4, 5, 6);

    // 内積
    double dot_product = v1.dot(v2);
    std::cout << "Dot product of v1 and v2: " << dot_product << std::endl;

    // 外積
    Eigen::Vector3d cross_product = v1.cross(v2);
    std::cout << "\nCross product of v1 and v2:\n" << cross_product << std::endl;
}

少し高度な使い方:連立一次方程式を解く

Eigenは、Ax = b の形で表される連立一次方程式を解くための強力なソルバーを備えています。行列 A とベクトル b が既知のとき、未知のベクトル x を求めます。

様々な解法が用意されていますが、一般的には LU分解QR分解 がよく使われます。

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

int main() {
    // 係数行列 A
    Eigen::Matrix3d A;
    A << 1, 2, 3,
         4, 5, 6,
         7, 8, 10;

    // 定数ベクトル b
    Eigen::Vector3d b(3, 3, 4);

    // Ax = b を解く
    // 様々な解法があるが、ここでは fullPivLu() を使う
    // .solve()メソッドで行列Aとベクトルbから解xを計算
    Eigen::Vector3d x = A.fullPivLu().solve(b);

    std::cout << "The solution x is:\n" << x << std::endl;

    // 検算
    double relative_error = (A * x - b).norm() / b.norm();
    std::cout << "The relative error is: " << relative_error << std::endl;
}

この例では、fullPivLu() を使ってLU分解を行い、その結果を使って .solve(b) で解 x を計算しています。他にも colPivHouseholderQr() (QR分解)など、行列の性質に応じて最適なソルバーを選択できます。

応用例

Eigenの強力な機能は、様々な分野で活用されています。

  • 3Dグラフィックス: 物体の移動、回転、拡大・縮小といった変換は、4x4の変換行列を用いて表現されます。Eigenの Matrix4fTransform クラスは、これらの処理を効率的に記述するのに役立ちます。
  • ロボティクス: ロボットアームの関節角度から先端位置を計算する順運動学や、その逆の逆運動学では、複雑な行列・ベクトル計算が必須です。
  • 機械学習: ニューラルネットワークの学習プロセスでは、巨大な行列の積や勾配計算が頻繁に行われます。GoogleのTensorFlowなど、多くの機械学習フレームワークの内部でEigenが利用されています。
  • 物理シミュレーション: 有限要素法(FEM)などのシミュレーションでは、大規模な連立一次方程式を解く必要があります。Eigenの疎行列サポートとソルバーが威力を発揮します。

まとめ

Eigenは、C++プログラミングにおける線形代数計算のデファクトスタンダードとも言えるライブラリです。その導入の手軽さ、卓越したパフォーマンス、そして直感的なAPIは、初心者からプロフェッショナルまで、幅広い開発者にとって大きな武器となります。

この記事で紹介したのはEigenの機能のほんの一部です。公式ドキュメントやチュートリアルには、さらに多くの高度な機能や詳細な使い方が解説されています。ベクトルや行列を扱う必要が出てきた際には、ぜひEigenの活用を検討してみてください。そのパワフルさと使いやすさに、きっと驚くことでしょう。

お仕事のご依頼・ご相談はこちら

フロントエンドからバックエンドまで、アプリケーション開発のご相談を承っております。
まずはお気軽にご連絡ください。

関連する記事

geometry3Sharpとは?C#で使える強力な3Dジオメトリ計算ライブラリを徹底解説

C#で3Dメッシュ処理や幾何計算を行いたい開発者必見!オープンソースライブラリ「geometry3Sharp」の機能、特徴、使い方、活用例をわかりやすく解説します。ゲーム開発、CAD、3Dプリンティング分野で役立ちます。

BootSharpとは?.NETをJavaScript環境で動かす新定番!使い方やBlazorとの違いを解説

BootSharpを使えば、C#で書いたコードをWebAssemblyを介してブラウザなどのJavaScript環境で簡単に実行できます。この記事では、BootSharpの基本的な使い方、Blazorとの違い、具体的な活用例を初心者にも分かりやすく解説します。UIフレームワークに縛られず、.NETのパワーをWebで活かしたい開発者必見です。

C#で動的コード実行!ExpressionEvaluatorライブラリを徹底解説

C#アプリケーションに、設定ファイルやユーザー入力から動的に数式評価やロジック実行機能を組み込みたいと思ったことはありませんか?本記事では、強力なC#ライブラリ「ExpressionEvaluator」について、その基本から応用まで、具体的なコード例を交えて詳しく解説します。

C++ Armadilloライブラリ徹底解説:インストールから実践的使い方まで

C++で高度な線形代数計算を簡単かつ高速に行いたいですか?この記事では、強力なC++ライブラリ「Armadillo」のインストール方法から、行列やベクトルの基本的な操作、連立一次方程式の解法、統計計算といった実践的な使い方まで、豊富なコード例と共に詳しく解説します。科学技術計算や機械学習の実装に役立つ知識を身につけましょう。

Google Cloudとは?主要サービスやメリットを初心者にもわかりやすく徹底解説

「Google Cloud(GCP)って何?」「何ができるの?」そんな疑問を解決します。この記事では、Google Cloudの基本的な概念から、主要なサービス、具体的なメリット、料金体系、そして始め方まで、初心者の方にも理解しやすいように丁寧に解説。ビジネスや開発にクラウドを活用したいと考えている方は必見です。

Bamba news