मैं ब्लॉकव्यू उलटा करने की कोशिश करूंगा।
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;
}
यहां दस लाख Eigen::Matrix<double,10,10>::Random()
मैट्रिस और Eigen::Matrix<double,10,1>::Random()
वैक्टर का उपयोग करके एक बेंच मार्क रन के परिणाम दिए गए हैं । मेरे सभी परीक्षणों में, मेरा व्युत्क्रम हमेशा तेज होता है। मेरी सुलझी हुई दिनचर्या में व्युत्क्रम की गणना करना और फिर इसे एक वेक्टर द्वारा गुणा करना शामिल है। कभी इजन से तेज तो कभी इसका। मेरी बेंच मार्किंग विधि त्रुटिपूर्ण हो सकती है (टर्बो बूस्ट को अक्षम न करें, आदि)। इसके अलावा, Eigen के यादृच्छिक कार्य वास्तविक डेटा के प्रतिनिधि नहीं हो सकते हैं।
- Eigen आंशिक धुरी व्युत्क्रम: 3036 मिलीसेकंड
- 8x8 ऊपरी ब्लॉक के साथ मेरा उलटा: 1638 मिलीसेकंड
- 6x6 ऊपरी ब्लॉक के साथ मेरा व्युत्क्रम: 1234 मिली सेकेंड
- Eigen आंशिक धुरी हल: 1791 मिलीसेकंड
- 8x8 ऊपरी ब्लॉक के साथ मेरा हल: 1739 मिलीसेकंड
- 6x6 ऊपरी ब्लॉक के साथ मेरा समाधान: 1286 मिलीसेकंड
मुझे यह देखने के लिए बहुत दिलचस्पी है कि क्या कोई इसे आगे भी अनुकूलित कर सकता है, क्योंकि मेरे पास एक परिमित तत्व अनुप्रयोग है जो एक gazillion 10x10 matrices (और हाँ, मुझे व्युत्क्रम के व्यक्तिगत गुणांक की आवश्यकता है, इसलिए सीधे एक रैखिक प्रणाली को हल करना एक विकल्प नहीं है) ।