ฉันจะลองทำสิ่งที่ตรงกันข้ามกับ Blockwise
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 ย้อนกลับ 8x8 โดยใช้รหัสผกผัน 4x4 ที่ปรับให้เหมาะสม ส่วนที่เหลือเป็นผลิตภัณฑ์เมทริกซ์
แก้ไข: การใช้บล็อค 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;
}
นี่คือผลลัพธ์ของการรัน bench bench หนึ่งครั้งโดยใช้Eigen::Matrix<double,10,10>::Random()
เมทริกซ์และEigen::Matrix<double,10,1>::Random()
เวกเตอร์หนึ่งล้านตัว ในการทดสอบทั้งหมดของฉันการผกผันของฉันจะเร็วกว่าเสมอ รูทีนการแก้ของฉันเกี่ยวข้องกับการคำนวณอินเวอร์สแล้วคูณมันด้วยเวกเตอร์ บางครั้งมันเร็วกว่า Eigen บางครั้งมันก็ไม่ได้ วิธีการทำเครื่องหมายผู้พิพากษาของฉันอาจมีข้อบกพร่อง (ไม่ได้ปิดการใช้งานเทอร์โบบูสต์ ฯลฯ ) นอกจากนี้ฟังก์ชั่นแบบสุ่มของ Eigen อาจไม่แสดงข้อมูลจริง
- Eigen pivot ผกผันบางส่วน: 3036 มิลลิวินาที
- ค่าผกผันของฉันกับบล็อกส่วนบน 8x8: 1638 มิลลิวินาที
- ค่าผกผันของฉันกับบล็อกส่วนบน 6x6: 1234 มิลลิวินาที
- Eigen เดือยบางส่วนแก้ปัญหา: 1791 มิลลิวินาที
- การแก้ปัญหาด้วยบล็อกส่วนบนของฉัน 8x8: 1739 มิลลิวินาที
- การแก้ปัญหาของฉันด้วยบล็อกส่วนบน 6x6: 1286 มิลลิวินาที
ฉันสนใจมากที่จะดูว่าใครสามารถเพิ่มประสิทธิภาพต่อไปนี้ได้เพราะฉันมีแอพพลิเคชั่นที่ จำกัด ซึ่งกลับค่าเมทริกซ์ 10x10 gazillion (และใช่ฉันต้องการค่าสัมประสิทธิ์ของอินเวอร์สทีละตัวดังนั้นการแก้ไขระบบเชิงเส้น .