私はブロックごとの反転を試みます。
https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion
Eigenは、最適化されたルーチンを使用して、4x4行列の逆行列を計算します。これは、おそらくあなたが得ようとしている最良のものです。可能な限り使用してみてください。
http://www.eigen.tuxfamily.org/dox/Inverse__SSE_8h_source.html
左上:8x8。右上:8x2。左下:2x8。右下:2x2。最適化された4x4反転コードを使用して8x8を反転します。残りはマトリックス製品です。
編集:6x6、6x4、4x6、および4x4ブロックを使用すると、上記で説明したものよりも少し高速であることが示されています。
using namespace Eigen;
template<typename Scalar, int tl_size, int br_size>
Matrix<Scalar, tl_size + br_size, tl_size + br_size> blockwise_inversion(const Matrix<Scalar, tl_size, tl_size>& A, const Matrix<Scalar, tl_size, br_size>& B, const Matrix<Scalar, br_size, tl_size>& C, const Matrix<Scalar, br_size, br_size>& D)
{
Matrix<Scalar, tl_size + br_size, tl_size + br_size> result;
Matrix<Scalar, tl_size, tl_size> A_inv = A.inverse().eval();
Matrix<Scalar, br_size, br_size> DCAB_inv = (D - C * A_inv * B).inverse();
result.topLeftCorner<tl_size, tl_size>() = A_inv + A_inv * B * DCAB_inv * C * A_inv;
result.topRightCorner<tl_size, br_size>() = -A_inv * B * DCAB_inv;
result.bottomLeftCorner<br_size, tl_size>() = -DCAB_inv * C * A_inv;
result.bottomRightCorner<br_size, br_size>() = DCAB_inv;
return result;
}
template<typename Scalar, int tl_size, int br_size>
Matrix<Scalar, tl_size + br_size, tl_size + br_size> my_inverse(const Matrix<Scalar, tl_size + br_size, tl_size + br_size>& mat)
{
const Matrix<Scalar, tl_size, tl_size>& A = mat.topLeftCorner<tl_size, tl_size>();
const Matrix<Scalar, tl_size, br_size>& B = mat.topRightCorner<tl_size, br_size>();
const Matrix<Scalar, br_size, tl_size>& C = mat.bottomLeftCorner<br_size, tl_size>();
const Matrix<Scalar, br_size, br_size>& D = mat.bottomRightCorner<br_size, br_size>();
return blockwise_inversion<Scalar,tl_size,br_size>(A, B, C, D);
}
template<typename Scalar>
Matrix<Scalar, 10, 10> invert_10_blockwise_8_2(const Matrix<Scalar, 10, 10>& input)
{
Matrix<Scalar, 10, 10> result;
const Matrix<Scalar, 8, 8>& A = input.topLeftCorner<8, 8>();
const Matrix<Scalar, 8, 2>& B = input.topRightCorner<8, 2>();
const Matrix<Scalar, 2, 8>& C = input.bottomLeftCorner<2, 8>();
const Matrix<Scalar, 2, 2>& D = input.bottomRightCorner<2, 2>();
Matrix<Scalar, 8, 8> A_inv = my_inverse<Scalar, 4, 4>(A);
Matrix<Scalar, 2, 2> DCAB_inv = (D - C * A_inv * B).inverse();
result.topLeftCorner<8, 8>() = A_inv + A_inv * B * DCAB_inv * C * A_inv;
result.topRightCorner<8, 2>() = -A_inv * B * DCAB_inv;
result.bottomLeftCorner<2, 8>() = -DCAB_inv * C * A_inv;
result.bottomRightCorner<2, 2>() = DCAB_inv;
return result;
}
template<typename Scalar>
Matrix<Scalar, 10, 10> invert_10_blockwise_6_4(const Matrix<Scalar, 10, 10>& input)
{
Matrix<Scalar, 10, 10> result;
const Matrix<Scalar, 6, 6>& A = input.topLeftCorner<6, 6>();
const Matrix<Scalar, 6, 4>& B = input.topRightCorner<6, 4>();
const Matrix<Scalar, 4, 6>& C = input.bottomLeftCorner<4, 6>();
const Matrix<Scalar, 4, 4>& D = input.bottomRightCorner<4, 4>();
Matrix<Scalar, 6, 6> A_inv = my_inverse<Scalar, 4, 2>(A);
Matrix<Scalar, 4, 4> DCAB_inv = (D - C * A_inv * B).inverse().eval();
result.topLeftCorner<6, 6>() = A_inv + A_inv * B * DCAB_inv * C * A_inv;
result.topRightCorner<6, 4>() = -A_inv * B * DCAB_inv;
result.bottomLeftCorner<4, 6>() = -DCAB_inv * C * A_inv;
result.bottomRightCorner<4, 4>() = DCAB_inv;
return result;
}
以下は、100万のEigen::Matrix<double,10,10>::Random()
行列とEigen::Matrix<double,10,1>::Random()
ベクトルを使用して実行された1つのベンチマークの結果です。すべての私のテストでは、私の逆は常に高速です。私の解決ルーチンは、逆を計算し、それをベクトルで乗算することを含みます。Eigenよりも速い場合もあれば、そうでない場合もあります。私のベンチマーキング方法に問題がある可能性があります(ターボブーストを無効にしていないなど)。また、アイゲンのランダム関数は実際のデータを表していない場合があります。
- 固有部分ピボット逆:3036ミリ秒
- 上部ブロックが8x8の逆数:1638ミリ秒
- 6x6の上部ブロックを持つ私の逆:1234ミリ秒
- 固有部分ピボット解決:1791ミリ秒
- 私の8x8上部ブロックでの解決:1739ミリ秒
- 6x6上部ブロックでの解決:1286ミリ秒
ガジリオンの10x10行列を反転する有限要素アプリケーションがあるので、これをさらに最適化できるかどうかに非常に興味があります(そうです、逆の個々の係数が必要なので、線形システムを直接解くことは必ずしもオプションではありません)。 。