一般化逆行列(擬似逆行列,最小二乗法に対応するやつ)をc++で計算するサンプル
特異値分解(SVD)が必要なので,実装は Eigen を使います
python/numpy の実装も用意しました.こちらです https://pyopyopyo.hatenablog.com/entry/2021/09/14/161955
#include <Eigen/Dense> #include <iostream> #include <random> #include <assert.h> int main() { //ランダムな 3x3 行列を生成 std::random_device rd; std::mt19937 gen(rd()); std::normal_distribution<float> dis(0, 10); //ラムダ式で乱数を生成,生成した値を行列の各要素に格納する Eigen::MatrixXf A = Eigen::MatrixXf::NullaryExpr(3,3, [&](){return dis(gen);}); // std::cout << "A: " << A << std::endl; Eigen::JacobiSVD<Eigen::MatrixXf> svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV); //std::cout << "U: " << svd.matrixU() << std::endl; //std::cout << "S: " << svd.singularValues() << std::endl; //std::cout << "V: " << svd.matrixV() << std::endl; // 一般化逆行列を計算する // // // svdで 行列A を U * S * V.T と分解しているから // // 一般化逆行列 A+ は V * S.T * U.T Eigen::VectorXf s = svd.singularValues(); s = s.array().inverse(); // 一般化逆行列の変数名は Ainv Eigen::MatrixXf Ainv = svd.matrixV() * s.asDiagonal() * svd.matrixU().transpose(); // A と A+ をかけると単位行列になる Eigen::MatrixXf m= A * Ainv; std::cout << m << std::endl; // 実際は,計算誤差があるので「ほぼ」単位行列になる. // そこで mとIdentity(3,3)が「ほぼ」等しいかEigenの isApprox() で確認 // 結果は assert()でチェック assert( Eigen::MatrixXf::Identity(3,3).isApprox(m) ); return 0;