Commit da5cd8b3 by Tobias WEBER

### improved/generalised inverse, lu, and qr calculations

parent 73f4ca07
 ... ... @@ -167,6 +167,10 @@ template using underlying_value_type = typename _underlying_value_type< template> std::tuple qr(const t_mat& mat) requires is_mat && is_vec; template std::tuple inv(const t_mat& mat) requires is_mat; // ---------------------------------------------------------------------------- ... ... @@ -464,6 +468,26 @@ requires is_basic_vec } /** * row permutation matrix */ template t_mat perm(std::size_t N1, std::size_t N2, std::size_t from, std::size_t to) requires is_basic_mat { t_mat mat; if constexpr(is_dyn_mat) mat = t_mat(N1, N2); unit(mat, 0,0, mat.size1(),mat.size2()); mat(from, from) = mat(to, to) = 0; mat(from, to) = mat(to, from) = 1; return mat; } /** * diagonal matrix */ ... ... @@ -1699,50 +1723,6 @@ requires is_mat } /** * inverted matrix */ template std::tuple inv(const t_mat& mat) requires is_mat { using T = typename t_mat::value_type; using t_vec = std::vector; const std::size_t N = mat.size1(); // fail if matrix is not square if(N != mat.size2()) return std::make_tuple(t_mat(), false); const t_vec matFlat = flatten(mat); const T fullDet = flat_det(matFlat, N); // fail if determinant is zero if(equals(fullDet, 0)) { //std::cerr << "det == 0" << std::endl; return std::make_tuple(t_mat(), false); } t_mat matInv; if constexpr(is_dyn_mat) matInv = t_mat(N, N); for(std::size_t i=0; i(matFlat, N, N, i, j); matInv(j,i) = sgn * flat_det(subMat, N-1); } } matInv = matInv / fullDet; return std::make_tuple(matInv, true); } /** * gets reciprocal basis vectors |b_i> from real basis vectors |a_i> (and vice versa) * c: multiplicative constant (c=2*pi for physical lattices, c=1 for mathematics) ... ... @@ -3924,8 +3904,151 @@ extern "C" namespace m_la { /** * QR decomposition of a matrix mat = QR * LU decomposition of a matrix, mat = P * L * U, returning raw results * http://www.math.utah.edu/software/lapack/lapack-d/dgetrf.html * return [ok, LU, perm] */ template class t_vec = std::vector> std::tuple, t_vec> _lu_raw(const t_mat& mat) requires m::is_mat { using namespace m_ops; using t_scalar = typename t_mat::value_type; using t_real = m::underlying_value_type; const std::size_t rows = mat.size1(); const std::size_t cols = mat.size2(); const std::size_t minor = std::min(rows, cols); t_vec outmat(rows*cols); t_vec outpivots(minor); for(std::size_t i=0; i) { if constexpr(std::is_same_v) err = LAPACKE_cgetrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outpivots.data()); else if constexpr(std::is_same_v) err = LAPACKE_zgetrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outpivots.data()); } else { if constexpr(std::is_same_v) err = LAPACKE_sgetrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outpivots.data()); else if constexpr(std::is_same_v) err = LAPACKE_dgetrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outpivots.data()); } return std::make_tuple(err == 0, outmat, outpivots); } /** * LU decomposition of a matrix, mat = P * L * U * http://www.math.utah.edu/software/lapack/lapack-d/dgetrf.html * return [ok, P, L, U] */ template class t_vec = std::vector> std::tuple lu(const t_mat& mat) requires m::is_mat { using namespace m_ops; using t_scalar = typename t_mat::value_type; using t_real = m::underlying_value_type; const std::size_t rows = mat.size1(); const std::size_t cols = mat.size2(); auto [ ok, lumat, pivots ] = _lu_raw(mat); t_mat P = m::unit(rows, cols); t_mat L = m::unit(rows, cols); t_mat U = m::unit(rows, cols); // L and U for(std::size_t i=0; i=i) U(i, j) = lumat[i*cols + j]; else L(i, j) = lumat[i*cols + j]; } } // permutation matrix P for(std::size_t i=0; i(P, m::perm(rows, cols, i, pivots[i]-1)); return std::make_tuple(ok, P, L, U); } /** * inverted matrix */ template std::tuple inv(const t_mat& mat) requires m::is_mat { // fail if matrix is not square if constexpr(m::is_dyn_mat) assert((mat.size1() == mat.size2())); else static_assert(mat.size1() == mat.size2()); using t_scalar = typename t_mat::value_type; using t_real = m::underlying_value_type; const std::size_t rows = mat.size1(); const std::size_t cols = mat.size2(); t_mat I = m::unit(rows, cols); // lu factorisation auto [ ok, lumat, pivots ] = _lu_raw(mat); if(!ok) return std::make_tuple(I, false); // inversion int err = -1; if constexpr(m::is_complex) { if constexpr(std::is_same_v) err = LAPACKE_cgetri(LAPACK_ROW_MAJOR, rows, lumat.data(), rows, pivots.data()); else if constexpr(std::is_same_v) err = LAPACKE_zgetri(LAPACK_ROW_MAJOR, rows, lumat.data(), rows, pivots.data()); } else { if constexpr(std::is_same_v) err = LAPACKE_sgetri(LAPACK_ROW_MAJOR, rows, lumat.data(), rows, pivots.data()); else if constexpr(std::is_same_v) err = LAPACKE_dgetri(LAPACK_ROW_MAJOR, rows, lumat.data(), rows, pivots.data()); } for(std::size_t i=0; i qr(const t_mat& mat) requires m::is_mat { using namespace m_ops; using T = typename t_mat::value_type; using t_scalar = typename t_mat::value_type; using t_real = m::underlying_value_type; const std::size_t rows = mat.size1(); const std::size_t cols = mat.size2(); ... ... @@ -3951,14 +4075,24 @@ requires m::is_mat outmat[i*cols + j] = mat(i, j); int err = -1; if constexpr(std::is_same_v) err = LAPACKE_sgeqrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outvec.data()); else if constexpr(std::is_same_v) err = LAPACKE_dgeqrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outvec.data()); if constexpr(m::is_complex) { if constexpr(std::is_same_v) err = LAPACKE_cgeqrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outvec.data()); else if constexpr(std::is_same_v) err = LAPACKE_zgeqrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outvec.data()); } else { if constexpr(std::is_same_v) err = LAPACKE_sgeqrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outvec.data()); else if constexpr(std::is_same_v) err = LAPACKE_dgeqrf(LAPACK_ROW_MAJOR, rows, cols, outmat.data(), cols, outvec.data()); } for(std::size_t i=0; i=i ? outmat[i*cols + j] : T{0}); R(i, j) = (j>=i ? outmat[i*cols + j] : t_real{0}); t_vec v = m::zero(minor); ... ... @@ -3966,8 +4100,8 @@ requires m::is_mat for(std::size_t k=1; k<=minor; ++k) { for(std::size_t i=1; i<=k-1; ++i) v[i-1] = T{0}; v[k-1] = T{1}; v[i-1] = t_real{0}; v[k-1] = t_real{1}; for(std::size_t i=k+1; i<=minor; ++i) v[i-1] = outmat[(i-1)*cols + (k-1)]; ... ... @@ -4280,7 +4414,7 @@ namespace m { /** * QR decomposition of a matrix * returns [Q, R] * returns [ok, Q, R] */ template> std::tuple qr(const t_mat& mat) ... ... @@ -4311,6 +4445,55 @@ requires is_mat && is_vec } /** * inverted matrix */ template std::tuple inv(const t_mat& mat) requires is_mat { // fail if matrix is not square if constexpr(m::is_dyn_mat) assert((mat.size1() == mat.size2())); else static_assert(mat.size1() == mat.size2()); #ifdef USE_LAPACK return m_la::inv(mat); #else using T = typename t_mat::value_type; using t_vec = std::vector; const std::size_t N = mat.size1(); const t_vec matFlat = flatten(mat); const T fullDet = flat_det(matFlat, N); // fail if determinant is zero if(equals(fullDet, 0)) { //std::cerr << "det == 0" << std::endl; return std::make_tuple(t_mat(), false); } t_mat matInv; if constexpr(is_dyn_mat) matInv = t_mat(N, N); for(std::size_t i=0; i(matFlat, N, N, i, j); matInv(j,i) = sgn * flat_det(subMat, N-1); } } matInv = matInv / fullDet; return std::make_tuple(matInv, true); #endif } /** * least-squares regression, solves for parameters v ... ...
 ... ... @@ -26,20 +26,45 @@ using t_mat_cplx = m::mat; int main() { auto M = m::create({1, 2, 3, 3, 2, 6, 4, 2, 4}); auto Z = m::create({1, 2, 3, 3, 2, 6, 4, 2, 4}); std::cout << "M = " << M << std::endl; std::cout << "Z = " << Z << std::endl; { auto [ok, Q, R] = m_la::qr(M); auto [ok2, P, L, U] = m_la::lu(M); std::cout << "\nok = " << std::boolalpha << ok << std::endl; std::cout << "Q = " << Q << std::endl; std::cout << "R = " << R << std::endl; std::cout << "QR = " << Q*R << std::endl; std::cout << "\nok2 = " << std::boolalpha << ok2 << std::endl; std::cout << "P = " << P << std::endl; std::cout << "L = " << L << std::endl; std::cout << "U = " << U << std::endl; std::cout << "PLU = " << P*L*U << std::endl; } { auto Z = m::create({1, 2, 3, 3, 2, 6, 4, 2, 4}); auto [ok, Q, R] = m_la::qr(Z); auto [ok2, P, L, U] = m_la::lu(Z); std::cout << "\nok = " << std::boolalpha << ok << std::endl; std::cout << "Q = " << Q << std::endl; std::cout << "R = " << R << std::endl; std::cout << "QR = " << Q*R << std::endl; std::cout << "\nok2 = " << std::boolalpha << ok2 << std::endl; std::cout << "P = " << P << std::endl; std::cout << "L = " << L << std::endl; std::cout << "U = " << U << std::endl; std::cout << "PLU = " << P*L*U << std::endl; } { auto [ok, evals, evecs] = m_la::eigenvec(Z, 0, 0, 1); std::cout << "\nok = " << std::boolalpha << ok << std::endl; for(std::size_t i=0; i({1, 2, 3, 3, 2, 6, 4, 2, 4}); auto [ok, evals_re, evals_im, evecs_re, evecs_im] = m_la::eigenvec(Z, 0, 0, 1); auto [ok, evals_re, evals_im, evecs_re, evecs_im] = m_la::eigenvec(M, 0, 0, 1); std::cout << "\nok = " << std::boolalpha << ok << std::endl; for(std::size_t i=0; i(Z); auto [ok2, U, Vt, vals] = m_la::singval(M); std::cout << "\nok = " << std::boolalpha << ok2 << std::endl; std::cout << "singvals: "; for(std::size_t i=0; i
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!