lu.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00024 #ifndef lu_h
00025 #define lu_h
00026 
00027 #include <cml/et/size_checking.h>
00028 #include <cml/matrix/matrix_expr.h>
00029 #include <cml/matvec/matvec_promotions.h>
00030 
00031 /* This is used below to create a more meaningful compile-time error when
00032  * lu is not provided with a matrix or MatrixExpr argument:
00033  */
00034 struct lu_expects_a_matrix_arg_error;
00035 
00036 /* This is used below to create a more meaningful compile-time error when
00037  * lu_inplace is not provided with an assignable matrix argument:
00038  */
00039 struct lu_inplace_expects_an_assignable_matrix_arg_error;
00040 
00041 namespace cml {
00042 namespace detail {
00043 
00044 /* Compute the LU decomposition in-place: */
00045 template<class MatT> inline
00046 void lu_inplace(MatT& A)
00047 {
00048     /* Shorthand: */
00049     typedef et::ExprTraits<MatT> arg_traits;
00050     typedef typename arg_traits::result_tag arg_result;
00051     typedef typename arg_traits::assignable_tag arg_assignment;
00052     typedef typename arg_traits::size_tag size_tag;
00053     typedef typename arg_traits::value_type value_type;
00054 
00055     /* lu_inplace() requires an assignable matrix expression: */
00056     CML_STATIC_REQUIRE_M(
00057         (same_type<arg_result, et::matrix_result_tag>::is_true
00058          && same_type<arg_assignment, et::assignable_tag>::is_true),
00059         lu_inplace_expects_an_assignable_matrix_arg_error);
00060     /* Note: parens are required here so that the preprocessor ignores the
00061      * commas.
00062      */
00063 
00064     /* Verify that the matrix is square, and get the size: */
00065     ssize_t N = (ssize_t) cml::et::CheckedSquare(A, size_tag());
00066 
00067 
00068     for(ssize_t k = 0; k < N-1; ++k) {
00069         /* XXX Should check if A(k,k) = 0! */
00070         for(ssize_t i = k+1; i < N; ++i) {
00071             value_type n = (A(i,k) /= A(k,k));
00072             for(ssize_t j = k+1; j < N; ++ j) {
00073                 A(i,j) -= n*A(k,j);
00074             }
00075         }
00076     }
00077 }
00078 
00079 /* Compute the LU decomposition, and return a copy of the result: */
00080 template<class MatT>
00081 inline typename MatT::temporary_type
00082 lu_copy(const MatT& M)
00083 {
00084     /* Shorthand: */
00085     typedef et::ExprTraits<MatT> arg_traits;
00086     typedef typename arg_traits::result_tag arg_result;
00087 
00088     /* lu_with_copy() requires a matrix expression: */
00089     CML_STATIC_REQUIRE_M(
00090         (same_type<arg_result, et::matrix_result_tag>::is_true),
00091         lu_expects_a_matrix_arg_error);
00092     /* Note: parens are required here so that the preprocessor ignores the
00093      * commas.
00094      */
00095 
00096     /* Use the in-place LU function, and return the result: */
00097     typename MatT::temporary_type A;
00098     cml::et::detail::Resize(A,M.rows(),M.cols());
00099     A = M;
00100     lu_inplace(A);
00101     return A;
00102 }
00103 
00104 } // namespace detail
00105 
00107 template<typename E, class AT, typename BO, class L>
00108 inline typename matrix<E,AT,BO,L>::temporary_type
00109 lu(const matrix<E,AT,BO,L>& m)
00110 {
00111     return detail::lu_copy(m);
00112 }
00113 
00115 template<typename XprT>
00116 inline typename et::MatrixXpr<XprT>::temporary_type
00117 lu(const et::MatrixXpr<XprT>& e)
00118 {
00119     return detail::lu_copy(e);
00120 }
00121 
00127 template<typename MatT, typename VecT> inline
00128 typename et::MatVecPromote<MatT,VecT>::temporary_type
00129 lu_solve(const MatT& LU, const VecT& b)
00130 {
00131     /* Shorthand. */
00132     typedef et::ExprTraits<MatT> lu_traits;
00133     typedef typename et::MatVecPromote<MatT,VecT>::temporary_type vector_type;
00134     typedef typename vector_type::value_type value_type;
00135 
00136     /* Verify that the matrix is square, and get the size: */
00137     ssize_t N = (ssize_t) cml::et::CheckedSquare(
00138             LU, typename lu_traits::size_tag());
00139 
00140     /* Verify that the matrix and vector have compatible sizes: */
00141     et::CheckedSize(LU, b, typename vector_type::size_tag());
00142 
00143     /* Solve Ly = b for y by forward substitution.  The entries below the
00144      * diagonal of LU correspond to L, understood to be below a diagonal of
00145      * 1's:
00146      */
00147     vector_type y; cml::et::detail::Resize(y,N);
00148     for(ssize_t i = 0; i < N; ++i) {
00149         y[i] = b[i];
00150         for(ssize_t j = 0; j < i; ++j) {
00151             y[i] -= LU(i,j)*y[j];
00152         }
00153     }
00154 
00155     /* Solve Ux = y for x by backward substitution.  The entries at and above
00156      * the diagonal of LU correspond to U:
00157      */
00158     vector_type x; cml::et::detail::Resize(x,N);
00159     for(ssize_t i = N-1; i >= 0; --i) {
00160         x[i] = y[i];
00161         for(ssize_t j = i+1; j < N; ++j) {
00162             x[i] -= LU(i,j)*x[j];
00163         }
00164         x[i] /= LU(i,i);
00165     }
00166 
00167     /* Return x: */
00168     return x;
00169 }
00170 
00171 } // namespace cml
00172 
00173 #endif
00174 
00175 // -------------------------------------------------------------------------
00176 // vim:ft=cpp

Generated on Sat Jul 18 19:35:23 2009 for CML 1.0 by  doxygen 1.5.9