Saya akan mencoba inversi blockwise.
https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion
Eigen menggunakan rutin yang dioptimalkan untuk menghitung kebalikan dari matriks 4x4, yang mungkin merupakan yang terbaik yang akan Anda dapatkan. Coba gunakan itu sebanyak mungkin.
http://www.eigen.tuxfamily.org/dox/Inverse__SSE_8h_source.html
Kiri atas: 8x8. Kanan atas: 8x2. Kiri bawah: 2x8. Kanan bawah: 2x2. Balikkan 8x8 menggunakan kode inversi 4x4 yang dioptimalkan. Sisanya adalah produk matriks.
EDIT: Menggunakan blok 6x6, 6x4, 4x6, dan 4x4 terbukti sedikit lebih cepat daripada yang saya jelaskan di atas.
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;
}
Berikut adalah hasil dari satu run mark bench menggunakan satu juta Eigen::Matrix<double,10,10>::Random()
matriks dan Eigen::Matrix<double,10,1>::Random()
vektor. Dalam semua pengujian saya, kebalikan saya selalu lebih cepat. Pemecahan rutin saya melibatkan menghitung invers dan kemudian mengalikannya dengan vektor. Terkadang lebih cepat dari Eigen, terkadang tidak. Metode menandai bangku saya mungkin cacat (tidak menonaktifkan turbo boost, dll). Juga, fungsi acak Eigen mungkin tidak mewakili data nyata.
- Pembalikan poros parsial eigen: 3036 milidetik
- Pembalikan saya dengan blok atas 8x8: 1638 milidetik
- Pembalikan saya dengan blok atas 6x6: 1234 milidetik
- Pivot parsial Eigen teratasi: 1791 milidetik
- Solusi saya dengan blok atas 8x8: 1739 milidetik
- Solusi saya dengan blok atas 6x6: 1286 milidetik
Saya sangat tertarik untuk melihat apakah ada yang bisa mengoptimalkan ini lebih lanjut, karena saya memiliki aplikasi elemen hingga yang membalikkan matriks 10x10 trilyun (dan ya, saya memang membutuhkan koefisien individu dari invers sehingga secara langsung menyelesaikan sistem linear tidak selalu merupakan pilihan) .