@@ -32,16 +32,16 @@ template <typename XprType_> class PartialPivLU {
3232 using Scalar = typename XprType::Scalar;
3333 public:
3434 // constructors
35- constexpr PartialPivLU () : lu_ (), P_(), info_(0 ), rank_(0 ) { }
35+ constexpr PartialPivLU () : L_(), U_ (), P_(), info_(0 ), rank_(0 ) { }
3636 template <typename XprType>
37- constexpr explicit PartialPivLU (const MatrixExpr<XprType>& m) : lu_ (), P_(), info_(0 ), rank_(0 ) {
37+ constexpr explicit PartialPivLU (const MatrixExpr<XprType>& m) : L_(), U_ (), P_(), info_(0 ), rank_(0 ) {
3838 compute (m);
3939 }
4040
4141 // build LU factorization of m via Doolittle LU with partial pivoting
4242 template <typename XprType> constexpr void compute (const MatrixExpr<XprType>& m) {
4343 const int n = m.rows ();
44- lu_ = m;
44+ Matrix<Scalar, Rows, Cols> lu = m;
4545 Scalar pivot_threshold = std::numeric_limits<Scalar>::epsilon () * m.inf_norm ();
4646 // initialization
4747 Vector<int , Rows> perm;
@@ -55,7 +55,7 @@ template <typename XprType_> class PartialPivLU {
5555 int pivot_index = k;
5656 Scalar max_val = Scalar (0 );
5757 for (int r = k; r < n; ++r) {
58- Scalar av = fdapde::abs (lu_ (r, k));
58+ Scalar av = fdapde::abs (lu (r, k));
5959 if (av > max_val) {
6060 max_val = av;
6161 pivot_index = r;
@@ -68,44 +68,48 @@ template <typename XprType_> class PartialPivLU {
6868 break ;
6969 }
7070 if (pivot_index != k) { // row swap
71- for (int c = 0 ; c < m.cols (); ++c) { std::swap (lu_ (k, c), lu_ (pivot_index, c)); }
71+ for (int c = 0 ; c < m.cols (); ++c) { std::swap (lu (k, c), lu (pivot_index, c)); }
7272 std::swap (perm[k], perm[pivot_index]);
7373 }
7474 // eliminate column below pivot
7575 for (int r = k + 1 ; r < n; ++r) {
76- Scalar alpha = lu_ (r, k) / lu_ (k, k);
77- lu_ (r, k) = alpha;
78- for (int c = k + 1 ; c < m.cols (); ++c) { lu_ (r, c) -= alpha * lu_ (k, c); }
76+ Scalar alpha = lu (r, k) / lu (k, k);
77+ lu (r, k) = alpha;
78+ for (int c = k + 1 ; c < m.cols (); ++c) { lu (r, c) -= alpha * lu (k, c); }
7979 }
8080 }
81+ L_ = lu.template triangular_block <Lower>();
82+ L_ .diagonal ().cwise () = 1 ; // L_ is unit-lower
83+ U_ = lu.template triangular_block <Upper>();
8184 P_ = PermutationMatrix<Rows, Cols>(perm);
8285 return ;
8386 }
8487 // observers
8588 constexpr const PermutationMatrix<Rows, Cols>& P () const { return P_ ; }
86- constexpr auto L () const { return lu_. template triangular_block <UnitLower>() ; }
87- constexpr auto U () const { return lu_. template triangular_block <Upper>() ; }
89+ constexpr auto L () const { return L_ ; }
90+ constexpr auto U () const { return U_ ; }
8891 constexpr int info () const { return info_; } // 0 = success, >0 = first zero pivot
8992 constexpr int rank () const { return rank_; }
9093 constexpr Scalar determinant () const {
9194 Scalar d = 1 ;
92- for (int i = 0 , n = lu_ .rows (); i < n; ++i) { d *= lu_ (i, i); }
95+ for (int i = 0 , n = U_ .rows (); i < n; ++i) { d *= U_ (i, i); }
9396 return P_ .determinant () * d;
9497 }
9598 // solve Ax = b via PA = LU
9699 template <typename RhsXprType> constexpr auto solve (const MatrixExpr<RhsXprType>& b) const {
97- fdapde_assert (b.rows () == lu_ .rows () && b.cols () > 0 );
100+ fdapde_assert (b.rows () == L_ . rows () && b. rows () == U_ .rows () && b.cols () > 0 );
98101 fdapde_assert (info_ == 0 );
99102
100103 constexpr int RhsRows = RhsXprType::Rows;
101104 constexpr int RhsCols = RhsXprType::Cols;
102105 Matrix<Scalar, RhsRows, RhsCols> y = P_ * b;
103- auto z = L () .solve (y); // forward substitute
104- auto x = U () .solve (z); // backward substitute
106+ auto z = L_ .solve (y); // forward substitute
107+ auto x = U_ .solve (z); // backward substitute
105108 return x;
106109 }
107110 private:
108- Matrix<Scalar, Rows, Cols, RowMajor> lu_; // holds both L (unit lower) and U (upper)
111+ TriangularMatrix<Scalar, Rows, Cols, Lower> L_ ;
112+ TriangularMatrix<Scalar, Rows, Cols, Upper> U_ ;
109113 PermutationMatrix<Rows, Cols> P_ ;
110114 int info_;
111115 int rank_;
0 commit comments