Tôi sẽ thử đảo ngược khối.
https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion
Eigen sử dụng một thói quen được tối ưu hóa để tính toán nghịch đảo của ma trận 4 x 4, đây có lẽ là điều tốt nhất bạn sẽ có được. Hãy thử sử dụng nó càng nhiều càng tốt.
http: //www.eigen.tuxf Family.org/dox/Inverse__SSE_8h_source.html
Trên cùng bên trái: 8x8. Trên cùng bên phải: 8x2. Dưới cùng bên trái: 2x8. Dưới cùng bên phải: 2x2. Đảo ngược 8x8 bằng cách sử dụng mã đảo ngược tối ưu hóa 4 x 4. Phần còn lại là sản phẩm ma trận.
EDIT: Sử dụng các khối 6x6, 6x4, 4x6 và 4x4 đã cho thấy nhanh hơn một chút so với những gì tôi mô tả ở trên.
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;
}
Dưới đây là kết quả của một lần chạy điểm chuẩn bằng cách sử dụng một triệu Eigen::Matrix<double,10,10>::Random()
ma trận và Eigen::Matrix<double,10,1>::Random()
vectơ. Trong tất cả các thử nghiệm của tôi, nghịch đảo của tôi luôn luôn nhanh hơn. Thói quen giải quyết của tôi liên quan đến việc tính toán nghịch đảo và sau đó nhân nó với một vectơ. Đôi khi nó nhanh hơn Eigen, đôi khi không. Phương pháp đánh dấu băng ghế của tôi có thể là thiếu sót (không vô hiệu hóa turbo boost, v.v.). Ngoài ra, các hàm ngẫu nhiên của Eigen có thể không đại diện cho dữ liệu thực.
- Đảo ngược một phần trục Eigen: 3036 mili giây
- Nghịch đảo của tôi với khối trên 8x8: 1638 mili giây
- Nghịch đảo của tôi với khối trên 6x6: 1234 mili giây
- Pigen giải quyết một phần trục: 1791 mili giây
- Giải quyết của tôi với khối trên 8x8: 1739 mili giây
- Giải quyết của tôi với khối trên 6x6: 1286 mili giây
Tôi rất quan tâm xem liệu có ai có thể tối ưu hóa điều này hơn nữa không, vì tôi có một ứng dụng phần tử hữu hạn giúp đảo ngược ma trận 10x10 (và vâng, tôi cần các hệ số riêng của nghịch đảo nên việc giải quyết trực tiếp một hệ tuyến tính không phải luôn luôn là một lựa chọn) .