J'essaierais l'inversion par blocs.
https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion
Eigen utilise une routine optimisée pour calculer l'inverse d'une matrice 4x4, qui est probablement la meilleure que vous obtiendrez. Essayez d'utiliser autant que possible.
http://www.eigen.tuxfamily.org/dox/Inverse__SSE_8h_source.html
En haut à gauche: 8x8. En haut à droite: 8x2. En bas à gauche: 2x8. En bas à droite: 2x2. Inversez le 8x8 en utilisant le code d'inversion 4x4 optimisé. Le reste est constitué de produits matriciels.
EDIT: L'utilisation de blocs 6x6, 6x4, 4x6 et 4x4 s'est avérée être un peu plus rapide que ce que j'ai décrit ci-dessus.
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;
}
Voici les résultats d'une analyse comparative utilisant un million de Eigen::Matrix<double,10,10>::Random()
matrices et de Eigen::Matrix<double,10,1>::Random()
vecteurs. Dans tous mes tests, mon inverse est toujours plus rapide. Ma routine de résolution consiste à calculer l'inverse puis à le multiplier par un vecteur. Parfois, c'est plus rapide que Eigen, parfois ce n'est pas le cas. Ma méthode de banc d'essai peut être défectueuse (n'a pas désactivé le turbo boost, etc.). De plus, les fonctions aléatoires d'Eigen peuvent ne pas être représentatives de données réelles.
- Inverse du pivot partiel propre: 3036 millisecondes
- Mon inverse avec bloc supérieur 8x8: 1638 millisecondes
- Mon inverse avec bloc supérieur 6x6: 1234 millisecondes
- Résolution de pivot partiel propre: 1791 millisecondes
- Ma résolution avec le bloc supérieur 8x8: 1739 millisecondes
- Ma résolution avec le bloc supérieur 6x6: 1286 millisecondes
Je suis très intéressé de voir si quelqu'un peut optimiser cela davantage, car j'ai une application par éléments finis qui inverse un million de matrices gazeuses 10x10 (et oui, j'ai besoin de coefficients individuels de l'inverse, donc résoudre directement un système linéaire n'est pas toujours une option) .