LinAlg デモ — 線形代数ソルバーの活用
LinAlg モジュールは直接法・反復法のソルバー、固有値分解、行列関数などを提供する。
Matrix<T> / Vector<T> と組み合わせて使う。
このページでは 4 つのデモを通じて、線形代数ソルバーの実用例を紹介する。 以下の出力はすべて calx で実際に計算したものである。 ソースコードはページ末尾に掲載しており、 calx をビルドすれば手元で同じ結果を確認できる。
Demo 1: 連立方程式 — LU / QR 統合インターフェース
連立方程式 $Ax = b$ を LU 分解と QR 分解の 2 つの方法で解く。
lu_solve() は直接呼び出し、solve() は統合インターフェースで
SolverType を指定して切り替えられる。
Demo 2: 対称行列の固有値分解
対称行列 $S$ の固有値と固有ベクトルを eigen_symmetric() で求める。
対称行列の固有値は常に実数であり、固有ベクトルは直交系を成す。
Demo 3: 行列指数関数 — 回転行列の生成
交代行列 (skew-symmetric) の行列指数関数 $e^A$ は回転行列になる。
expm() で $2 \times 2$ の交代行列から回転行列を生成する。
Demo 4: 共役勾配法 — 反復ソルバー
対称正定値 (SPD) 行列に対して、conjugate_gradient() で反復的に解を求める。
直接法と異なり、行列を陽に分解せずに行列ベクトル積だけで解ける。
大規模疎行列に適する。
$5 \times 5$ の対角優位対称行列(三重対角)を構成する:
$$A = \begin{pmatrix} 10 & -1 & & & \\ -1 & 10 & -1 & & \\ & -1 & 10 & -1 & \\ & & -1 & 10 & -1 \\ & & & -1 & 10 \end{pmatrix}, \quad b = \begin{pmatrix} 1 \\ 1 \\ 1 \\ 1 \\ 1 \end{pmatrix}$$ソースコードと実行方法
このページの全出力は以下の C++ プログラムから生成された。 calx をビルドすれば、手元で同じ結果を確認できる。
example_linalg.cpp (クリックで展開/折りたたみ)
// example_linalg.cpp
// Demonstrates linear algebra features from the calx API reference.
//
// Build:
// cd build && cmake --build . --config Release --target example-linalg
#include <math/core/matrix.hpp>
#include <math/core/vector.hpp>
#include <math/linalg/solvers.hpp>
#include <math/linalg/eigenvalues.hpp>
#include <math/linalg/matrix_functions.hpp>
#include <iostream>
#include <cmath>
using namespace calx;
using namespace calx::algorithms;
// ---------------------------------------------------------------------------
// Snippet 1: Solve a linear system Ax = b (LU + unified interface)
// ---------------------------------------------------------------------------
void demo_linear_solve() {
std::cout << "=== demo_linear_solve ===" << std::endl;
Matrix<double> A({{2, 1, -1},
{-3, -1, 2},
{-2, 1, 2}});
Vector<double> b({8, -11, -3});
// LU solver
auto x = lu_solve(A, b);
std::cout << "x (LU) = [";
for (std::size_t i = 0; i < x.size(); ++i)
std::cout << " " << x[i];
std::cout << " ]" << std::endl;
// Unified interface with QR
auto x2 = solve(A, b, SolverType::QR);
std::cout << "x (QR) = [";
for (std::size_t i = 0; i < x2.size(); ++i)
std::cout << " " << x2[i];
std::cout << " ]" << std::endl;
std::cout << std::endl;
}
// ---------------------------------------------------------------------------
// Snippet 2: Eigenvalue decomposition of a symmetric matrix
// ---------------------------------------------------------------------------
void demo_eigen_symmetric() {
std::cout << "=== demo_eigen_symmetric ===" << std::endl;
Matrix<double> S({{4, 1, 1},
{1, 3, 0},
{1, 0, 2}});
auto [eigenvalues, eigenvectors] = eigen_symmetric(S);
std::cout << "eigenvalues = [";
for (std::size_t i = 0; i < eigenvalues.size(); ++i)
std::cout << " " << eigenvalues[i];
std::cout << " ]" << std::endl;
std::cout << "eigenvectors (columns):" << std::endl;
for (std::size_t i = 0; i < eigenvectors.rows(); ++i) {
std::cout << " [";
for (std::size_t j = 0; j < eigenvectors.cols(); ++j)
std::cout << " " << eigenvectors(i, j);
std::cout << " ]" << std::endl;
}
std::cout << std::endl;
}
// ---------------------------------------------------------------------------
// Snippet 3: Matrix exponential (rotation matrix from skew-symmetric)
// ---------------------------------------------------------------------------
void demo_expm() {
std::cout << "=== demo_expm ===" << std::endl;
Matrix<double> A({{0, -1},
{1, 0}});
auto E = expm(A);
std::cout << "expm(A) =" << std::endl;
for (std::size_t i = 0; i < E.rows(); ++i) {
std::cout << " [";
for (std::size_t j = 0; j < E.cols(); ++j)
std::cout << " " << E(i, j);
std::cout << " ]" << std::endl;
}
std::cout << "expected: [[ " << std::cos(1.0) << " " << -std::sin(1.0)
<< " ] [ " << std::sin(1.0) << " " << std::cos(1.0) << " ]]"
<< std::endl;
std::cout << std::endl;
}
// ---------------------------------------------------------------------------
// Snippet 4: Iterative solver (CG on a symmetric positive-definite matrix)
// ---------------------------------------------------------------------------
void demo_iterative_solver() {
std::cout << "=== demo_iterative_solver ===" << std::endl;
const int n = 5;
Matrix<double> A(n, n, 0.0);
for (int i = 0; i < n; ++i) {
A(i, i) = 10.0;
if (i > 0) { A(i, i - 1) = -1.0; A(i - 1, i) = -1.0; }
}
Vector<double> b(n, 1.0);
auto x = conjugate_gradient(A, b, 1e-12, 5000);
std::cout << "x (CG) = [";
for (std::size_t i = 0; i < x.size(); ++i)
std::cout << " " << x[i];
std::cout << " ]" << std::endl;
// Verify residual
auto r = A * x;
double res = 0.0;
for (std::size_t i = 0; i < b.size(); ++i)
res += (r[i] - b[i]) * (r[i] - b[i]);
std::cout << "||Ax - b|| = " << std::sqrt(res) << std::endl;
std::cout << std::endl;
}
// ---------------------------------------------------------------------------
int main() {
demo_linear_solve();
demo_eigen_symmetric();
demo_expm();
demo_iterative_solver();
return 0;
}
API の詳細は LinAlg API リファレンス を参照のこと。
ビルドと実行
cd build && cmake --build . --config Release --target example-linalg