sl@0: // sl@0: // Copyright (c) 2000-2002 sl@0: // Joerg Walter, Mathias Koch sl@0: // sl@0: // Permission to use, copy, modify, distribute and sell this software sl@0: // and its documentation for any purpose is hereby granted without fee, sl@0: // provided that the above copyright notice appear in all copies and sl@0: // that both that copyright notice and this permission notice appear sl@0: // in supporting documentation. The authors make no representations sl@0: // about the suitability of this software for any purpose. sl@0: // It is provided "as is" without express or implied warranty. sl@0: // sl@0: // The authors gratefully acknowledge the support of sl@0: // GeNeSys mbH & Co. KG in producing this work. sl@0: // sl@0: sl@0: #ifndef _BOOST_UBLAS_LU_ sl@0: #define _BOOST_UBLAS_LU_ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: // LU factorizations in the spirit of LAPACK and Golub & van Loan sl@0: sl@0: namespace boost { namespace numeric { namespace ublas { sl@0: sl@0: template > sl@0: class permutation_matrix: sl@0: public vector { sl@0: public: sl@0: typedef vector vector_type; sl@0: typedef typename vector_type::size_type size_type; sl@0: sl@0: // Construction and destruction sl@0: BOOST_UBLAS_INLINE sl@0: permutation_matrix (size_type size): sl@0: vector (size) { sl@0: for (size_type i = 0; i < size; ++ i) sl@0: (*this) (i) = i; sl@0: } sl@0: BOOST_UBLAS_INLINE sl@0: ~permutation_matrix () {} sl@0: sl@0: // Assignment sl@0: BOOST_UBLAS_INLINE sl@0: permutation_matrix &operator = (const permutation_matrix &m) { sl@0: vector_type::operator = (m); sl@0: return *this; sl@0: } sl@0: }; sl@0: sl@0: template sl@0: BOOST_UBLAS_INLINE sl@0: void swap_rows (const PM &pm, MV &mv, vector_tag) { sl@0: typedef typename PM::size_type size_type; sl@0: typedef typename MV::value_type value_type; sl@0: sl@0: size_type size = pm.size (); sl@0: for (size_type i = 0; i < size; ++ i) { sl@0: if (i != pm (i)) sl@0: std::swap (mv (i), mv (pm (i))); sl@0: } sl@0: } sl@0: template sl@0: BOOST_UBLAS_INLINE sl@0: void swap_rows (const PM &pm, MV &mv, matrix_tag) { sl@0: typedef typename PM::size_type size_type; sl@0: typedef typename MV::value_type value_type; sl@0: sl@0: size_type size = pm.size (); sl@0: for (size_type i = 0; i < size; ++ i) { sl@0: if (i != pm (i)) sl@0: row (mv, i).swap (row (mv, pm (i))); sl@0: } sl@0: } sl@0: // Dispatcher sl@0: template sl@0: BOOST_UBLAS_INLINE sl@0: void swap_rows (const PM &pm, MV &mv) { sl@0: swap_rows (pm, mv, typename MV::type_category ()); sl@0: } sl@0: sl@0: // LU factorization without pivoting sl@0: template sl@0: typename M::size_type lu_factorize (M &m) { sl@0: typedef M matrix_type; sl@0: typedef typename M::size_type size_type; sl@0: typedef typename M::value_type value_type; sl@0: sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: matrix_type cm (m); sl@0: #endif sl@0: int singular = 0; sl@0: size_type size1 = m.size1 (); sl@0: size_type size2 = m.size2 (); sl@0: size_type size = (std::min) (size1, size2); sl@0: for (size_type i = 0; i < size; ++ i) { sl@0: matrix_column mci (column (m, i)); sl@0: matrix_row mri (row (m, i)); sl@0: if (m (i, i) != value_type/*zero*/()) { sl@0: project (mci, range (i + 1, size1)) *= value_type (1) / m (i, i); sl@0: } else if (singular == 0) { sl@0: singular = i + 1; sl@0: } sl@0: project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign ( sl@0: outer_prod (project (mci, range (i + 1, size1)), sl@0: project (mri, range (i + 1, size2)))); sl@0: } sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (singular != 0 || sl@0: detail::expression_type_check (prod (triangular_adaptor (m), sl@0: triangular_adaptor (m)), sl@0: cm), internal_logic ()); sl@0: #endif sl@0: return singular; sl@0: } sl@0: sl@0: // LU factorization with partial pivoting sl@0: template sl@0: typename M::size_type lu_factorize (M &m, PM &pm) { sl@0: typedef M matrix_type; sl@0: typedef typename M::size_type size_type; sl@0: typedef typename M::value_type value_type; sl@0: sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: matrix_type cm (m); sl@0: #endif sl@0: int singular = 0; sl@0: size_type size1 = m.size1 (); sl@0: size_type size2 = m.size2 (); sl@0: size_type size = (std::min) (size1, size2); sl@0: for (size_type i = 0; i < size; ++ i) { sl@0: matrix_column mci (column (m, i)); sl@0: matrix_row mri (row (m, i)); sl@0: size_type i_norm_inf = i + index_norm_inf (project (mci, range (i, size1))); sl@0: BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ()); sl@0: if (m (i_norm_inf, i) != value_type/*zero*/()) { sl@0: if (i_norm_inf != i) { sl@0: pm (i) = i_norm_inf; sl@0: row (m, i_norm_inf).swap (mri); sl@0: } else { sl@0: BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ()); sl@0: } sl@0: project (mci, range (i + 1, size1)) *= value_type (1) / m (i, i); sl@0: } else if (singular == 0) { sl@0: singular = i + 1; sl@0: } sl@0: project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign ( sl@0: outer_prod (project (mci, range (i + 1, size1)), sl@0: project (mri, range (i + 1, size2)))); sl@0: } sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: swap_rows (pm, cm); sl@0: BOOST_UBLAS_CHECK (singular != 0 || sl@0: detail::expression_type_check (prod (triangular_adaptor (m), sl@0: triangular_adaptor (m)), cm), internal_logic ()); sl@0: #endif sl@0: return singular; sl@0: } sl@0: sl@0: template sl@0: typename M::size_type axpy_lu_factorize (M &m, PM &pm) { sl@0: typedef M matrix_type; sl@0: typedef typename M::size_type size_type; sl@0: typedef typename M::value_type value_type; sl@0: typedef vector vector_type; sl@0: sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: matrix_type cm (m); sl@0: #endif sl@0: int singular = 0; sl@0: size_type size1 = m.size1 (); sl@0: size_type size2 = m.size2 (); sl@0: size_type size = (std::min) (size1, size2); sl@0: #ifndef BOOST_UBLAS_LU_WITH_INPLACE_SOLVE sl@0: matrix_type mr (m); sl@0: mr.assign (zero_matrix (size1, size2)); sl@0: vector_type v (size1); sl@0: for (size_type i = 0; i < size; ++ i) { sl@0: matrix_range lrr (project (mr, range (0, i), range (0, i))); sl@0: vector_range > urr (project (column (mr, i), range (0, i))); sl@0: urr.assign (solve (lrr, project (column (m, i), range (0, i)), unit_lower_tag ())); sl@0: project (v, range (i, size1)).assign ( sl@0: project (column (m, i), range (i, size1)) - sl@0: axpy_prod (project (mr, range (i, size1), range (0, i)), urr)); sl@0: size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1))); sl@0: BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ()); sl@0: if (v (i_norm_inf) != value_type/*zero*/()) { sl@0: if (i_norm_inf != i) { sl@0: pm (i) = i_norm_inf; sl@0: std::swap (v (i_norm_inf), v (i)); sl@0: project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2))); sl@0: } else { sl@0: BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ()); sl@0: } sl@0: project (column (mr, i), range (i + 1, size1)).assign ( sl@0: project (v, range (i + 1, size1)) / v (i)); sl@0: if (i_norm_inf != i) { sl@0: project (row (mr, i_norm_inf), range (0, i)).swap (project (row (mr, i), range (0, i))); sl@0: } sl@0: } else if (singular == 0) { sl@0: singular = i + 1; sl@0: } sl@0: mr (i, i) = v (i); sl@0: } sl@0: m.assign (mr); sl@0: #else sl@0: matrix_type lr (m); sl@0: matrix_type ur (m); sl@0: lr.assign (identity_matrix (size1, size2)); sl@0: ur.assign (zero_matrix (size1, size2)); sl@0: vector_type v (size1); sl@0: for (size_type i = 0; i < size; ++ i) { sl@0: matrix_range lrr (project (lr, range (0, i), range (0, i))); sl@0: vector_range > urr (project (column (ur, i), range (0, i))); sl@0: urr.assign (project (column (m, i), range (0, i))); sl@0: inplace_solve (lrr, urr, unit_lower_tag ()); sl@0: project (v, range (i, size1)).assign ( sl@0: project (column (m, i), range (i, size1)) - sl@0: axpy_prod (project (lr, range (i, size1), range (0, i)), urr)); sl@0: size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1))); sl@0: BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ()); sl@0: if (v (i_norm_inf) != value_type/*zero*/()) { sl@0: if (i_norm_inf != i) { sl@0: pm (i) = i_norm_inf; sl@0: std::swap (v (i_norm_inf), v (i)); sl@0: project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2))); sl@0: } else { sl@0: BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ()); sl@0: } sl@0: project (column (lr, i), range (i + 1, size1)).assign ( sl@0: project (v, range (i + 1, size1)) / v (i)); sl@0: if (i_norm_inf != i) { sl@0: project (row (lr, i_norm_inf), range (0, i)).swap (project (row (lr, i), range (0, i))); sl@0: } sl@0: } else if (singular == 0) { sl@0: singular = i + 1; sl@0: } sl@0: ur (i, i) = v (i); sl@0: } sl@0: m.assign (triangular_adaptor (lr) + sl@0: triangular_adaptor (ur)); sl@0: #endif sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: swap_rows (pm, cm); sl@0: BOOST_UBLAS_CHECK (singular != 0 || sl@0: detail::expression_type_check (prod (triangular_adaptor (m), sl@0: triangular_adaptor (m)), cm), internal_logic ()); sl@0: #endif sl@0: return singular; sl@0: } sl@0: sl@0: // LU substitution sl@0: template sl@0: void lu_substitute (const M &m, vector_expression &e) { sl@0: typedef const M const_matrix_type; sl@0: typedef vector vector_type; sl@0: sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: vector_type cv1 (e); sl@0: #endif sl@0: inplace_solve (m, e, unit_lower_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor (m), e), cv1), internal_logic ()); sl@0: vector_type cv2 (e); sl@0: #endif sl@0: inplace_solve (m, e, upper_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor (m), e), cv2), internal_logic ()); sl@0: #endif sl@0: } sl@0: template sl@0: void lu_substitute (const M &m, matrix_expression &e) { sl@0: typedef const M const_matrix_type; sl@0: typedef matrix matrix_type; sl@0: sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: matrix_type cm1 (e); sl@0: #endif sl@0: inplace_solve (m, e, unit_lower_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor (m), e), cm1), internal_logic ()); sl@0: matrix_type cm2 (e); sl@0: #endif sl@0: inplace_solve (m, e, upper_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor (m), e), cm2), internal_logic ()); sl@0: #endif sl@0: } sl@0: template sl@0: void lu_substitute (const M &m, const permutation_matrix &pm, MV &mv) { sl@0: swap_rows (pm, mv); sl@0: lu_substitute (m, mv); sl@0: } sl@0: template sl@0: void lu_substitute (vector_expression &e, const M &m) { sl@0: typedef const M const_matrix_type; sl@0: typedef vector vector_type; sl@0: sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: vector_type cv1 (e); sl@0: #endif sl@0: inplace_solve (e, m, upper_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor (m)), cv1), internal_logic ()); sl@0: vector_type cv2 (e); sl@0: #endif sl@0: inplace_solve (e, m, unit_lower_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor (m)), cv2), internal_logic ()); sl@0: #endif sl@0: } sl@0: template sl@0: void lu_substitute (matrix_expression &e, const M &m) { sl@0: typedef const M const_matrix_type; sl@0: typedef matrix matrix_type; sl@0: sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: matrix_type cm1 (e); sl@0: #endif sl@0: inplace_solve (e, m, upper_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor (m)), cm1), internal_logic ()); sl@0: matrix_type cm2 (e); sl@0: #endif sl@0: inplace_solve (e, m, unit_lower_tag ()); sl@0: #if BOOST_UBLAS_TYPE_CHECK sl@0: BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor (m)), cm2), internal_logic ()); sl@0: #endif sl@0: } sl@0: template sl@0: void lu_substitute (MV &mv, const M &m, const permutation_matrix &pm) { sl@0: swap_rows (pm, mv); sl@0: lu_substitute (mv, m); sl@0: } sl@0: sl@0: }}} sl@0: sl@0: #endif