// L============================================================================= // L This software is distributed under the MIT license. // L Copyright 2021 Péter Kardos // L============================================================================= #pragma once #include "../Common/MathUtil.hpp" #include "../Transforms/IdentityBuilder.hpp" #include "../Transforms/ZeroBuilder.hpp" namespace mathter { /// A utility class that can do common operations with the QR decomposition, /// i.e. solving equation systems. template class DecompositionQR { using MatrixT = Matrix; public: // DecompositionQR(Matrix Q, // Matrix R) : Q(Q), R(R) {} Matrix Q; Matrix R; }; /// Calculates the QR decomposition of the matrix using Householder transforms. /// The matrix must have Rows <= Columns. It's a full QR decomposition, not a thin one. template auto DecomposeQR(Matrix m) { static_assert(Rows >= Columns); Matrix Q; Matrix R; R = m; Q = Identity(); Matrix Qi; Vector u; Matrix v; for (int col = 0; col < m.ColumnCount(); ++col) { u = R.Column(col); for (int i = 0; i < col; ++i) { u(i) = T(0); } T alpha = impl::sign(R(col, col)) * LengthPrecise(u); u(col) -= alpha; T norm = LengthPrecise(u); if (norm == 0) { continue; } u /= norm; v = u; Qi = (T(-2) * v) * Transpose(v); for (int i = 0; i < Q.ColumnCount(); ++i) { Qi(i, i) += T(1); } R = Qi * R; Q = Qi * Q; } Q = Transpose(Q); return DecompositionQR{ Q, R }; } } // namespace mathter