lu.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //
  2. // Copyright (c) 2000-2002
  3. // Joerg Walter, Mathias Koch
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // The authors gratefully acknowledge the support of
  10. // GeNeSys mbH & Co. KG in producing this work.
  11. //
  12. #ifndef _BOOST_UBLAS_LU_
  13. #define _BOOST_UBLAS_LU_
  14. #include <boost/numeric/ublas/operation.hpp>
  15. #include <boost/numeric/ublas/vector_proxy.hpp>
  16. #include <boost/numeric/ublas/matrix_proxy.hpp>
  17. #include <boost/numeric/ublas/vector.hpp>
  18. #include <boost/numeric/ublas/triangular.hpp>
  19. // LU factorizations in the spirit of LAPACK and Golub & van Loan
  20. namespace boost { namespace numeric { namespace ublas {
  21. /** \brief
  22. *
  23. * \tparam T
  24. * \tparam A
  25. */
  26. template<class T = std::size_t, class A = unbounded_array<T> >
  27. class permutation_matrix:
  28. public vector<T, A> {
  29. public:
  30. typedef vector<T, A> vector_type;
  31. typedef typename vector_type::size_type size_type;
  32. // Construction and destruction
  33. BOOST_UBLAS_INLINE
  34. explicit
  35. permutation_matrix (size_type size):
  36. vector<T, A> (size) {
  37. for (size_type i = 0; i < size; ++ i)
  38. (*this) (i) = i;
  39. }
  40. BOOST_UBLAS_INLINE
  41. explicit
  42. permutation_matrix (const vector_type & init)
  43. : vector_type(init)
  44. { }
  45. BOOST_UBLAS_INLINE
  46. ~permutation_matrix () {}
  47. // Assignment
  48. BOOST_UBLAS_INLINE
  49. permutation_matrix &operator = (const permutation_matrix &m) {
  50. vector_type::operator = (m);
  51. return *this;
  52. }
  53. };
  54. template<class PM, class MV>
  55. BOOST_UBLAS_INLINE
  56. void swap_rows (const PM &pm, MV &mv, vector_tag) {
  57. typedef typename PM::size_type size_type;
  58. typedef typename MV::value_type value_type;
  59. size_type size = pm.size ();
  60. for (size_type i = 0; i < size; ++ i) {
  61. if (i != pm (i))
  62. std::swap (mv (i), mv (pm (i)));
  63. }
  64. }
  65. template<class PM, class MV>
  66. BOOST_UBLAS_INLINE
  67. void swap_rows (const PM &pm, MV &mv, matrix_tag) {
  68. typedef typename PM::size_type size_type;
  69. typedef typename MV::value_type value_type;
  70. size_type size = pm.size ();
  71. for (size_type i = 0; i < size; ++ i) {
  72. if (i != pm (i))
  73. row (mv, i).swap (row (mv, pm (i)));
  74. }
  75. }
  76. // Dispatcher
  77. template<class PM, class MV>
  78. BOOST_UBLAS_INLINE
  79. void swap_rows (const PM &pm, MV &mv) {
  80. swap_rows (pm, mv, typename MV::type_category ());
  81. }
  82. // LU factorization without pivoting
  83. template<class M>
  84. typename M::size_type lu_factorize (M &m) {
  85. typedef M matrix_type;
  86. typedef typename M::size_type size_type;
  87. typedef typename M::value_type value_type;
  88. #if BOOST_UBLAS_TYPE_CHECK
  89. matrix_type cm (m);
  90. #endif
  91. size_type singular = 0;
  92. size_type size1 = m.size1 ();
  93. size_type size2 = m.size2 ();
  94. size_type size = (std::min) (size1, size2);
  95. for (size_type i = 0; i < size; ++ i) {
  96. matrix_column<M> mci (column (m, i));
  97. matrix_row<M> mri (row (m, i));
  98. if (m (i, i) != value_type/*zero*/()) {
  99. value_type m_inv = value_type (1) / m (i, i);
  100. project (mci, range (i + 1, size1)) *= m_inv;
  101. } else if (singular == 0) {
  102. singular = i + 1;
  103. }
  104. project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign (
  105. outer_prod (project (mci, range (i + 1, size1)),
  106. project (mri, range (i + 1, size2))));
  107. }
  108. #if BOOST_UBLAS_TYPE_CHECK
  109. BOOST_UBLAS_CHECK (singular != 0 ||
  110. detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
  111. triangular_adaptor<matrix_type, upper> (m)),
  112. cm), internal_logic ());
  113. #endif
  114. return singular;
  115. }
  116. // LU factorization with partial pivoting
  117. template<class M, class PM>
  118. typename M::size_type lu_factorize (M &m, PM &pm) {
  119. typedef M matrix_type;
  120. typedef typename M::size_type size_type;
  121. typedef typename M::value_type value_type;
  122. #if BOOST_UBLAS_TYPE_CHECK
  123. matrix_type cm (m);
  124. #endif
  125. size_type singular = 0;
  126. size_type size1 = m.size1 ();
  127. size_type size2 = m.size2 ();
  128. size_type size = (std::min) (size1, size2);
  129. for (size_type i = 0; i < size; ++ i) {
  130. matrix_column<M> mci (column (m, i));
  131. matrix_row<M> mri (row (m, i));
  132. size_type i_norm_inf = i + index_norm_inf (project (mci, range (i, size1)));
  133. BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
  134. if (m (i_norm_inf, i) != value_type/*zero*/()) {
  135. if (i_norm_inf != i) {
  136. pm (i) = i_norm_inf;
  137. row (m, i_norm_inf).swap (mri);
  138. } else {
  139. BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
  140. }
  141. value_type m_inv = value_type (1) / m (i, i);
  142. project (mci, range (i + 1, size1)) *= m_inv;
  143. } else if (singular == 0) {
  144. singular = i + 1;
  145. }
  146. project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign (
  147. outer_prod (project (mci, range (i + 1, size1)),
  148. project (mri, range (i + 1, size2))));
  149. }
  150. #if BOOST_UBLAS_TYPE_CHECK
  151. swap_rows (pm, cm);
  152. BOOST_UBLAS_CHECK (singular != 0 ||
  153. detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
  154. triangular_adaptor<matrix_type, upper> (m)), cm), internal_logic ());
  155. #endif
  156. return singular;
  157. }
  158. template<class M, class PM>
  159. typename M::size_type axpy_lu_factorize (M &m, PM &pm) {
  160. typedef M matrix_type;
  161. typedef typename M::size_type size_type;
  162. typedef typename M::value_type value_type;
  163. typedef vector<value_type> vector_type;
  164. #if BOOST_UBLAS_TYPE_CHECK
  165. matrix_type cm (m);
  166. #endif
  167. size_type singular = 0;
  168. size_type size1 = m.size1 ();
  169. size_type size2 = m.size2 ();
  170. size_type size = (std::min) (size1, size2);
  171. #ifndef BOOST_UBLAS_LU_WITH_INPLACE_SOLVE
  172. matrix_type mr (m);
  173. mr.assign (zero_matrix<value_type> (size1, size2));
  174. vector_type v (size1);
  175. for (size_type i = 0; i < size; ++ i) {
  176. matrix_range<matrix_type> lrr (project (mr, range (0, i), range (0, i)));
  177. vector_range<matrix_column<matrix_type> > urr (project (column (mr, i), range (0, i)));
  178. urr.assign (solve (lrr, project (column (m, i), range (0, i)), unit_lower_tag ()));
  179. project (v, range (i, size1)).assign (
  180. project (column (m, i), range (i, size1)) -
  181. axpy_prod<vector_type> (project (mr, range (i, size1), range (0, i)), urr));
  182. size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1)));
  183. BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
  184. if (v (i_norm_inf) != value_type/*zero*/()) {
  185. if (i_norm_inf != i) {
  186. pm (i) = i_norm_inf;
  187. std::swap (v (i_norm_inf), v (i));
  188. project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2)));
  189. } else {
  190. BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
  191. }
  192. project (column (mr, i), range (i + 1, size1)).assign (
  193. project (v, range (i + 1, size1)) / v (i));
  194. if (i_norm_inf != i) {
  195. project (row (mr, i_norm_inf), range (0, i)).swap (project (row (mr, i), range (0, i)));
  196. }
  197. } else if (singular == 0) {
  198. singular = i + 1;
  199. }
  200. mr (i, i) = v (i);
  201. }
  202. m.assign (mr);
  203. #else
  204. matrix_type lr (m);
  205. matrix_type ur (m);
  206. lr.assign (identity_matrix<value_type> (size1, size2));
  207. ur.assign (zero_matrix<value_type> (size1, size2));
  208. vector_type v (size1);
  209. for (size_type i = 0; i < size; ++ i) {
  210. matrix_range<matrix_type> lrr (project (lr, range (0, i), range (0, i)));
  211. vector_range<matrix_column<matrix_type> > urr (project (column (ur, i), range (0, i)));
  212. urr.assign (project (column (m, i), range (0, i)));
  213. inplace_solve (lrr, urr, unit_lower_tag ());
  214. project (v, range (i, size1)).assign (
  215. project (column (m, i), range (i, size1)) -
  216. axpy_prod<vector_type> (project (lr, range (i, size1), range (0, i)), urr));
  217. size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1)));
  218. BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
  219. if (v (i_norm_inf) != value_type/*zero*/()) {
  220. if (i_norm_inf != i) {
  221. pm (i) = i_norm_inf;
  222. std::swap (v (i_norm_inf), v (i));
  223. project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2)));
  224. } else {
  225. BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
  226. }
  227. project (column (lr, i), range (i + 1, size1)).assign (
  228. project (v, range (i + 1, size1)) / v (i));
  229. if (i_norm_inf != i) {
  230. project (row (lr, i_norm_inf), range (0, i)).swap (project (row (lr, i), range (0, i)));
  231. }
  232. } else if (singular == 0) {
  233. singular = i + 1;
  234. }
  235. ur (i, i) = v (i);
  236. }
  237. m.assign (triangular_adaptor<matrix_type, strict_lower> (lr) +
  238. triangular_adaptor<matrix_type, upper> (ur));
  239. #endif
  240. #if BOOST_UBLAS_TYPE_CHECK
  241. swap_rows (pm, cm);
  242. BOOST_UBLAS_CHECK (singular != 0 ||
  243. detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
  244. triangular_adaptor<matrix_type, upper> (m)), cm), internal_logic ());
  245. #endif
  246. return singular;
  247. }
  248. // LU substitution
  249. template<class M, class E>
  250. void lu_substitute (const M &m, vector_expression<E> &e) {
  251. typedef const M const_matrix_type;
  252. typedef vector<typename E::value_type> vector_type;
  253. #if BOOST_UBLAS_TYPE_CHECK
  254. vector_type cv1 (e);
  255. #endif
  256. inplace_solve (m, e, unit_lower_tag ());
  257. #if BOOST_UBLAS_TYPE_CHECK
  258. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, unit_lower> (m), e), cv1), internal_logic ());
  259. vector_type cv2 (e);
  260. #endif
  261. inplace_solve (m, e, upper_tag ());
  262. #if BOOST_UBLAS_TYPE_CHECK
  263. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, upper> (m), e), cv2), internal_logic ());
  264. #endif
  265. }
  266. template<class M, class E>
  267. void lu_substitute (const M &m, matrix_expression<E> &e) {
  268. typedef const M const_matrix_type;
  269. typedef matrix<typename E::value_type> matrix_type;
  270. #if BOOST_UBLAS_TYPE_CHECK
  271. matrix_type cm1 (e);
  272. #endif
  273. inplace_solve (m, e, unit_lower_tag ());
  274. #if BOOST_UBLAS_TYPE_CHECK
  275. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, unit_lower> (m), e), cm1), internal_logic ());
  276. matrix_type cm2 (e);
  277. #endif
  278. inplace_solve (m, e, upper_tag ());
  279. #if BOOST_UBLAS_TYPE_CHECK
  280. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, upper> (m), e), cm2), internal_logic ());
  281. #endif
  282. }
  283. template<class M, class PMT, class PMA, class MV>
  284. void lu_substitute (const M &m, const permutation_matrix<PMT, PMA> &pm, MV &mv) {
  285. swap_rows (pm, mv);
  286. lu_substitute (m, mv);
  287. }
  288. template<class E, class M>
  289. void lu_substitute (vector_expression<E> &e, const M &m) {
  290. typedef const M const_matrix_type;
  291. typedef vector<typename E::value_type> vector_type;
  292. #if BOOST_UBLAS_TYPE_CHECK
  293. vector_type cv1 (e);
  294. #endif
  295. inplace_solve (e, m, upper_tag ());
  296. #if BOOST_UBLAS_TYPE_CHECK
  297. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, upper> (m)), cv1), internal_logic ());
  298. vector_type cv2 (e);
  299. #endif
  300. inplace_solve (e, m, unit_lower_tag ());
  301. #if BOOST_UBLAS_TYPE_CHECK
  302. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, unit_lower> (m)), cv2), internal_logic ());
  303. #endif
  304. }
  305. template<class E, class M>
  306. void lu_substitute (matrix_expression<E> &e, const M &m) {
  307. typedef const M const_matrix_type;
  308. typedef matrix<typename E::value_type> matrix_type;
  309. #if BOOST_UBLAS_TYPE_CHECK
  310. matrix_type cm1 (e);
  311. #endif
  312. inplace_solve (e, m, upper_tag ());
  313. #if BOOST_UBLAS_TYPE_CHECK
  314. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, upper> (m)), cm1), internal_logic ());
  315. matrix_type cm2 (e);
  316. #endif
  317. inplace_solve (e, m, unit_lower_tag ());
  318. #if BOOST_UBLAS_TYPE_CHECK
  319. BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, unit_lower> (m)), cm2), internal_logic ());
  320. #endif
  321. }
  322. template<class MV, class M, class PMT, class PMA>
  323. void lu_substitute (MV &mv, const M &m, const permutation_matrix<PMT, PMA> &pm) {
  324. swap_rows (pm, mv);
  325. lu_substitute (mv, m);
  326. }
  327. }}}
  328. #endif