Blok ters çevirme denerdim.
https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion
Eigen, muhtemelen elde edeceğiniz en iyi olan 4x4 matrisinin tersini hesaplamak için optimize edilmiş bir rutin kullanır. Bunu mümkün olduğunca kullanmayı deneyin.
http://www.eigen.tuxfamily.org/dox/Inverse__SSE_8h_source.html
Sol üst: 8x8. Sağ üst: 8x2. Sol alttaki: 2x8. Sağ alttaki: 2x2. Optimize edilmiş 4x4 ters çevirme kodunu kullanarak 8x8'i ters çevirin. Gerisi matris ürünleridir.
DÜZENLEME: 6x6, 6x4, 4x6 ve 4x4 bloklarını kullanmanın yukarıda tarif ettiğimden biraz daha hızlı olduğu gösterilmiştir.
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;
}
İşte bir milyon Eigen::Matrix<double,10,10>::Random()
matris ve Eigen::Matrix<double,10,1>::Random()
vektör kullanılarak bir bench mark çalışmasının sonuçları . Tüm testlerimde, tersim her zaman daha hızlıdır. Benim çözme rutinim tersi hesaplamak ve daha sonra bir vektör ile çarpmaktır. Bazen Eigen'den daha hızlı, bazen değil. Tezgah markalama yöntemim kusurlu olabilir (turbo güçlendirmeyi devre dışı bırakmadı, vb.). Ayrıca, Eigen'ın rastgele işlevleri gerçek verileri temsil etmeyebilir.
- Eigen kısmi pivot tersi: 3036 milisaniye
- 8x8 üst blok ile tersim: 1638 milisaniye
- 6x6 üst blok ile tersim: 1234 milisaniye
- Öz kısmi pivot çözme: 1791 milisaniye
- 8x8 üst blok ile çözdüğüm: 1739 milisaniye
- 6x6 üst blok ile çözdüğüm: 1286 milisaniye
Bir gazilyon 10x10 matrisini tersine çeviren sonlu bir eleman uygulamam olduğu için herkesin bunu daha da optimize edip edemeyeceğini görmekle çok ilgiliyim (ve evet, tersin bireysel katsayılarına ihtiyacım var, bu yüzden doğrudan doğrusal bir sistemi çözmek her zaman bir seçenek değildir) .