Ich würde blockweise Inversion versuchen.
https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion
Eigen verwendet eine optimierte Routine, um die Inverse einer 4x4-Matrix zu berechnen. Dies ist wahrscheinlich die beste, die Sie erhalten werden. Versuchen Sie das so oft wie möglich zu verwenden.
http://www.eigen.tuxfamily.org/dox/Inverse__SSE_8h_source.html
Oben links: 8x8. Oben rechts: 8x2. Unten links: 2x8. Unten rechts: 2x2. Invertieren Sie das 8x8 mit dem optimierten 4x4-Inversionscode. Der Rest sind Matrixprodukte.
BEARBEITEN: Die Verwendung von 6x6-, 6x4-, 4x6- und 4x4-Blöcken hat sich als etwas schneller erwiesen als oben beschrieben.
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;
}
Hier sind die Ergebnisse eines Benchmark-Laufs mit einer Million Eigen::Matrix<double,10,10>::Random()
Matrizen und Eigen::Matrix<double,10,1>::Random()
Vektoren. Bei all meinen Tests ist meine Umkehrung immer schneller. Meine Lösungsroutine besteht darin, das Inverse zu berechnen und es dann mit einem Vektor zu multiplizieren. Manchmal ist es schneller als Eigen, manchmal nicht. Meine Benchmarking-Methode ist möglicherweise fehlerhaft (Turbo-Boost usw. wurde nicht deaktiviert). Außerdem sind Eigens Zufallsfunktionen möglicherweise nicht repräsentativ für reale Daten.
- Eigener partieller Pivot invers: 3036 Millisekunden
- Meine Umkehrung mit 8x8 oberem Block: 1638 Millisekunden
- Meine Umkehrung mit 6x6 oberem Block: 1234 Millisekunden
- Eigene partielle Pivot-Lösung: 1791 Millisekunden
- Meine Lösung mit 8x8 oberen Block: 1739 Millisekunden
- Meine Lösung mit 6x6 oberen Block: 1286 Millisekunden
Ich bin sehr interessiert zu sehen, ob jemand dies weiter optimieren kann, da ich eine Finite-Elemente-Anwendung habe, die eine Unmenge von 10x10-Matrizen invertiert (und ja, ich benötige einzelne Koeffizienten der Inversen, so dass das direkte Lösen eines linearen Systems nicht immer eine Option ist). .