00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef MTL_UPPER_TRISOLVE_INCLUDE
00013 #define MTL_UPPER_TRISOLVE_INCLUDE
00014
00015 #include <boost/numeric/mtl/utility/tag.hpp>
00016 #include <boost/numeric/mtl/utility/exception.hpp>
00017 #include <boost/numeric/mtl/utility/property_map.hpp>
00018 #include <boost/numeric/mtl/utility/range_generator.hpp>
00019 #include <boost/numeric/mtl/utility/category.hpp>
00020 #include <boost/numeric/mtl/concept/collection.hpp>
00021 #include <boost/numeric/mtl/operation/adjust_cursor.hpp>
00022
00023 #include <boost/numeric/linear_algebra/identity.hpp>
00024
00025 namespace mtl { namespace matrix {
00026
00027
00028 namespace detail {
00029
00030
00031 template <typename Matrix, typename DiaTag>
00032 struct upper_trisolve_t
00033 {
00034 typedef typename Collection<Matrix>::value_type value_type;
00035 typedef typename Collection<Matrix>::size_type size_type;
00036 typedef typename OrientedCollection<Matrix>::orientation my_orientation;
00037 typedef typename mtl::traits::category<Matrix>::type my_category;
00038
00039 upper_trisolve_t(const Matrix& A) : A(A), value_a(A), col_a(A), row_a(A)
00040 {
00041 MTL_THROW_IF(num_rows(A) != num_cols(A), matrix_not_square());
00042 }
00043
00044 template <typename Vector>
00045 Vector operator()(const Vector& v)
00046 {
00047 return apply(v, my_orientation());
00048 }
00049
00050 private:
00051
00052 template <typename Cursor>
00053 void row_init(size_type r, Cursor& aic, Cursor& aiend, value_type& dia, tag::universe_diagonal)
00054 {
00055 MTL_DEBUG_THROW_IF(aic == aiend || col_a(*aic) != r, missing_diagonal());
00056 dia= value_a(*aic); ++aic;
00057 }
00058
00059 template <typename Cursor>
00060 void row_init(size_type r, Cursor& aic, Cursor&, value_type&, tag::unit_diagonal) {}
00061
00062 void row_update(value_type& res, value_type& rr, const value_type& dia, tag::regular_diagonal) { res= rr / dia; }
00063 void row_update(value_type& res, value_type& rr, const value_type& dia, tag::inverse_diagonal) { res= rr * dia; }
00064 void row_update(value_type& res, value_type& rr, const value_type& dia, tag::unit_diagonal) { res= rr; }
00065
00066 template <typename Tag> int dia_inc(Tag) { return 0; }
00067 int dia_inc(tag::unit_diagonal) { return 1; }
00068
00069 template <typename Vector>
00070 Vector inline apply(const Vector& v, tag::row_major)
00071 {
00072 using namespace tag; using mtl::traits::range_generator; using math::one;
00073 typedef typename range_generator<row, Matrix>::type ra_cur_type;
00074 typedef typename range_generator<nz, ra_cur_type>::type ra_icur_type;
00075
00076 Vector result(v);
00077
00078 ra_cur_type ac= begin<row>(A), aend= end<row>(A);
00079 for (size_type r= num_rows(A) - 1; ac != aend--; --r) {
00080 ra_icur_type aic= lower_bound<nz>(aend, r + dia_inc(DiaTag())), aiend= end<nz>(aend);
00081 value_type rr= result[r], dia;
00082 row_init(r, aic, aiend, dia, DiaTag());
00083 for (; aic != aiend; ++aic) {
00084 MTL_DEBUG_THROW_IF(col_a(*aic) <= r, logic_error("Matrix entries must be sorted for this."));
00085 rr-= value_a(*aic) * result[col_a(*aic)];
00086 }
00087 row_update(result[r], rr, dia, DiaTag());
00088 }
00089 return result;
00090 }
00091
00092
00093 template <typename Vector>
00094 Vector apply(const Vector& v, tag::col_major)
00095 {
00096 using namespace tag; using mtl::traits::range_generator; using math::one;
00097 typedef typename range_generator<col, Matrix>::type ca_cur_type;
00098 typedef typename range_generator<nz, ca_cur_type>::type ca_icur_type;
00099
00100 Vector result(v);
00101
00102 ca_cur_type ac= begin<col>(A), aend= end<col>(A);
00103 for (size_type r= num_rows(A) - 1; ac != aend--; --r) {
00104 ca_icur_type aic= begin<nz>(aend), aiend= lower_bound<nz>(aend, r + 1 - dia_inc(DiaTag()));
00105 value_type rr;
00106 col_init(r, aic, aiend, rr, result[r], DiaTag());
00107
00108 for (; aic != aiend; ++aic) {
00109 MTL_DEBUG_THROW_IF(row_a(*aic) >= r, logic_error("Matrix entries must be sorted for this."));
00110 result[row_a(*aic)]-= value_a(*aic) * rr;
00111 }
00112 }
00113 return result;
00114 }
00115
00116 template <typename Cursor>
00117 void col_init(size_type r, Cursor& aic, Cursor& aiend, value_type& rr, value_type& res, tag::regular_diagonal)
00118 {
00119 MTL_DEBUG_THROW_IF(aic == aiend, missing_diagonal());
00120 --aiend;
00121 MTL_DEBUG_THROW_IF(row_a(*aiend) != r, missing_diagonal());
00122 rr= res/= value_a(*aiend);
00123 }
00124
00125 template <typename Cursor>
00126 void col_init(size_type r, Cursor& aic, Cursor& aiend, value_type& rr, value_type& res, tag::inverse_diagonal)
00127 {
00128 MTL_DEBUG_THROW_IF(aic == aiend, missing_diagonal());
00129 --aiend;
00130 MTL_DEBUG_THROW_IF(row_a(*aiend) != r, missing_diagonal());
00131 rr= res*= value_a(*aiend);
00132 }
00133
00134 template <typename Cursor>
00135 void col_init(size_type r, Cursor& aic, Cursor& aiend, value_type& rr, value_type& res, tag::unit_diagonal)
00136 {
00137 rr= res;
00138 }
00139
00140
00141 const Matrix& A;
00142 typename mtl::traits::const_value<Matrix>::type value_a;
00143 typename mtl::traits::col<Matrix>::type col_a;
00144 typename mtl::traits::row<Matrix>::type row_a;
00145 };
00146
00147 }
00148
00150 template <typename Matrix, typename Vector>
00151 Vector inline upper_trisolve(const Matrix& A, const Vector& v)
00152 {
00153 return detail::upper_trisolve_t<Matrix, tag::regular_diagonal>(A)(v);
00154 }
00156 template <typename Matrix, typename Vector>
00157 Vector inline unit_upper_trisolve(const Matrix& A, const Vector& v)
00158 {
00159 return detail::upper_trisolve_t<Matrix, tag::unit_diagonal>(A)(v);
00160 }
00162 template <typename Matrix, typename Vector>
00163 Vector inline inverse_upper_trisolve(const Matrix& A, const Vector& v)
00164 {
00165 return detail::upper_trisolve_t<Matrix, tag::inverse_diagonal>(A)(v);
00166 }
00168 template <typename Matrix, typename Vector, typename DiaTag>
00169 Vector inline upper_trisolve(const Matrix& A, const Vector& v, DiaTag)
00170 {
00171 return detail::upper_trisolve_t<Matrix, DiaTag>(A)(v);
00172 }
00173
00174 }}
00175
00176 #endif // MTL_UPPER_TRISOLVE_INCLUDE