operation.hpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  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_OPERATION_
  13. #define _BOOST_UBLAS_OPERATION_
  14. #include <boost/numeric/ublas/matrix_proxy.hpp>
  15. /** \file operation.hpp
  16. * \brief This file contains some specialized products.
  17. */
  18. // axpy-based products
  19. // Alexei Novakov had a lot of ideas to improve these. Thanks.
  20. // Hendrik Kueck proposed some new kernel. Thanks again.
  21. namespace boost { namespace numeric { namespace ublas {
  22. template<class V, class T1, class L1, class IA1, class TA1, class E2>
  23. BOOST_UBLAS_INLINE
  24. V &
  25. axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
  26. const vector_expression<E2> &e2,
  27. V &v, row_major_tag) {
  28. typedef typename V::size_type size_type;
  29. typedef typename V::value_type value_type;
  30. for (size_type i = 0; i < e1.filled1 () -1; ++ i) {
  31. size_type begin = e1.index1_data () [i];
  32. size_type end = e1.index1_data () [i + 1];
  33. value_type t (v (i));
  34. for (size_type j = begin; j < end; ++ j)
  35. t += e1.value_data () [j] * e2 () (e1.index2_data () [j]);
  36. v (i) = t;
  37. }
  38. return v;
  39. }
  40. template<class V, class T1, class L1, class IA1, class TA1, class E2>
  41. BOOST_UBLAS_INLINE
  42. V &
  43. axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
  44. const vector_expression<E2> &e2,
  45. V &v, column_major_tag) {
  46. typedef typename V::size_type size_type;
  47. for (size_type j = 0; j < e1.filled1 () -1; ++ j) {
  48. size_type begin = e1.index1_data () [j];
  49. size_type end = e1.index1_data () [j + 1];
  50. for (size_type i = begin; i < end; ++ i)
  51. v (e1.index2_data () [i]) += e1.value_data () [i] * e2 () (j);
  52. }
  53. return v;
  54. }
  55. // Dispatcher
  56. template<class V, class T1, class L1, class IA1, class TA1, class E2>
  57. BOOST_UBLAS_INLINE
  58. V &
  59. axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
  60. const vector_expression<E2> &e2,
  61. V &v, bool init = true) {
  62. typedef typename V::value_type value_type;
  63. typedef typename L1::orientation_category orientation_category;
  64. if (init)
  65. v.assign (zero_vector<value_type> (e1.size1 ()));
  66. #if BOOST_UBLAS_TYPE_CHECK
  67. vector<value_type> cv (v);
  68. typedef typename type_traits<value_type>::real_type real_type;
  69. real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
  70. indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
  71. #endif
  72. axpy_prod (e1, e2, v, orientation_category ());
  73. #if BOOST_UBLAS_TYPE_CHECK
  74. BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
  75. #endif
  76. return v;
  77. }
  78. template<class V, class T1, class L1, class IA1, class TA1, class E2>
  79. BOOST_UBLAS_INLINE
  80. V
  81. axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
  82. const vector_expression<E2> &e2) {
  83. typedef V vector_type;
  84. vector_type v (e1.size1 ());
  85. return axpy_prod (e1, e2, v, true);
  86. }
  87. template<class V, class T1, class L1, class IA1, class TA1, class E2>
  88. BOOST_UBLAS_INLINE
  89. V &
  90. axpy_prod (const coordinate_matrix<T1, L1, 0, IA1, TA1> &e1,
  91. const vector_expression<E2> &e2,
  92. V &v, bool init = true) {
  93. typedef typename V::size_type size_type;
  94. typedef typename V::value_type value_type;
  95. typedef L1 layout_type;
  96. size_type size1 = e1.size1();
  97. size_type size2 = e1.size2();
  98. if (init) {
  99. noalias(v) = zero_vector<value_type>(size1);
  100. }
  101. for (size_type i = 0; i < e1.nnz(); ++i) {
  102. size_type row_index = layout_type::index_M( e1.index1_data () [i], e1.index2_data () [i] );
  103. size_type col_index = layout_type::index_m( e1.index1_data () [i], e1.index2_data () [i] );
  104. v( row_index ) += e1.value_data () [i] * e2 () (col_index);
  105. }
  106. return v;
  107. }
  108. template<class V, class E1, class E2>
  109. BOOST_UBLAS_INLINE
  110. V &
  111. axpy_prod (const matrix_expression<E1> &e1,
  112. const vector_expression<E2> &e2,
  113. V &v, packed_random_access_iterator_tag, row_major_tag) {
  114. typedef const E1 expression1_type;
  115. typedef typename V::size_type size_type;
  116. typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
  117. typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
  118. while (it1 != it1_end) {
  119. size_type index1 (it1.index1 ());
  120. #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  121. typename expression1_type::const_iterator2 it2 (it1.begin ());
  122. typename expression1_type::const_iterator2 it2_end (it1.end ());
  123. #else
  124. typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
  125. typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
  126. #endif
  127. while (it2 != it2_end) {
  128. v (index1) += *it2 * e2 () (it2.index2 ());
  129. ++ it2;
  130. }
  131. ++ it1;
  132. }
  133. return v;
  134. }
  135. template<class V, class E1, class E2>
  136. BOOST_UBLAS_INLINE
  137. V &
  138. axpy_prod (const matrix_expression<E1> &e1,
  139. const vector_expression<E2> &e2,
  140. V &v, packed_random_access_iterator_tag, column_major_tag) {
  141. typedef const E1 expression1_type;
  142. typedef typename V::size_type size_type;
  143. typename expression1_type::const_iterator2 it2 (e1 ().begin2 ());
  144. typename expression1_type::const_iterator2 it2_end (e1 ().end2 ());
  145. while (it2 != it2_end) {
  146. size_type index2 (it2.index2 ());
  147. #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  148. typename expression1_type::const_iterator1 it1 (it2.begin ());
  149. typename expression1_type::const_iterator1 it1_end (it2.end ());
  150. #else
  151. typename expression1_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
  152. typename expression1_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
  153. #endif
  154. while (it1 != it1_end) {
  155. v (it1.index1 ()) += *it1 * e2 () (index2);
  156. ++ it1;
  157. }
  158. ++ it2;
  159. }
  160. return v;
  161. }
  162. template<class V, class E1, class E2>
  163. BOOST_UBLAS_INLINE
  164. V &
  165. axpy_prod (const matrix_expression<E1> &e1,
  166. const vector_expression<E2> &e2,
  167. V &v, sparse_bidirectional_iterator_tag) {
  168. typedef const E2 expression2_type;
  169. typename expression2_type::const_iterator it (e2 ().begin ());
  170. typename expression2_type::const_iterator it_end (e2 ().end ());
  171. while (it != it_end) {
  172. v.plus_assign (column (e1 (), it.index ()) * *it);
  173. ++ it;
  174. }
  175. return v;
  176. }
  177. // Dispatcher
  178. template<class V, class E1, class E2>
  179. BOOST_UBLAS_INLINE
  180. V &
  181. axpy_prod (const matrix_expression<E1> &e1,
  182. const vector_expression<E2> &e2,
  183. V &v, packed_random_access_iterator_tag) {
  184. typedef typename E1::orientation_category orientation_category;
  185. return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
  186. }
  187. /** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
  188. optimized fashion.
  189. \param e1 the matrix expression \c A
  190. \param e2 the vector expression \c x
  191. \param v the result vector \c v
  192. \param init a boolean parameter
  193. <tt>axpy_prod(A, x, v, init)</tt> implements the well known
  194. axpy-product. Setting \a init to \c true is equivalent to call
  195. <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
  196. defaults to \c true, but this may change in the future.
  197. Up to now there are some specialisation for compressed
  198. matrices that give a large speed up compared to prod.
  199. \ingroup blas2
  200. \internal
  201. template parameters:
  202. \param V type of the result vector \c v
  203. \param E1 type of a matrix expression \c A
  204. \param E2 type of a vector expression \c x
  205. */
  206. template<class V, class E1, class E2>
  207. BOOST_UBLAS_INLINE
  208. V &
  209. axpy_prod (const matrix_expression<E1> &e1,
  210. const vector_expression<E2> &e2,
  211. V &v, bool init = true) {
  212. typedef typename V::value_type value_type;
  213. typedef typename E2::const_iterator::iterator_category iterator_category;
  214. if (init)
  215. v.assign (zero_vector<value_type> (e1 ().size1 ()));
  216. #if BOOST_UBLAS_TYPE_CHECK
  217. vector<value_type> cv (v);
  218. typedef typename type_traits<value_type>::real_type real_type;
  219. real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
  220. indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
  221. #endif
  222. axpy_prod (e1, e2, v, iterator_category ());
  223. #if BOOST_UBLAS_TYPE_CHECK
  224. BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
  225. #endif
  226. return v;
  227. }
  228. template<class V, class E1, class E2>
  229. BOOST_UBLAS_INLINE
  230. V
  231. axpy_prod (const matrix_expression<E1> &e1,
  232. const vector_expression<E2> &e2) {
  233. typedef V vector_type;
  234. vector_type v (e1 ().size1 ());
  235. return axpy_prod (e1, e2, v, true);
  236. }
  237. template<class V, class E1, class T2, class IA2, class TA2>
  238. BOOST_UBLAS_INLINE
  239. V &
  240. axpy_prod (const vector_expression<E1> &e1,
  241. const compressed_matrix<T2, column_major, 0, IA2, TA2> &e2,
  242. V &v, column_major_tag) {
  243. typedef typename V::size_type size_type;
  244. typedef typename V::value_type value_type;
  245. for (size_type j = 0; j < e2.filled1 () -1; ++ j) {
  246. size_type begin = e2.index1_data () [j];
  247. size_type end = e2.index1_data () [j + 1];
  248. value_type t (v (j));
  249. for (size_type i = begin; i < end; ++ i)
  250. t += e2.value_data () [i] * e1 () (e2.index2_data () [i]);
  251. v (j) = t;
  252. }
  253. return v;
  254. }
  255. template<class V, class E1, class T2, class IA2, class TA2>
  256. BOOST_UBLAS_INLINE
  257. V &
  258. axpy_prod (const vector_expression<E1> &e1,
  259. const compressed_matrix<T2, row_major, 0, IA2, TA2> &e2,
  260. V &v, row_major_tag) {
  261. typedef typename V::size_type size_type;
  262. for (size_type i = 0; i < e2.filled1 () -1; ++ i) {
  263. size_type begin = e2.index1_data () [i];
  264. size_type end = e2.index1_data () [i + 1];
  265. for (size_type j = begin; j < end; ++ j)
  266. v (e2.index2_data () [j]) += e2.value_data () [j] * e1 () (i);
  267. }
  268. return v;
  269. }
  270. // Dispatcher
  271. template<class V, class E1, class T2, class L2, class IA2, class TA2>
  272. BOOST_UBLAS_INLINE
  273. V &
  274. axpy_prod (const vector_expression<E1> &e1,
  275. const compressed_matrix<T2, L2, 0, IA2, TA2> &e2,
  276. V &v, bool init = true) {
  277. typedef typename V::value_type value_type;
  278. typedef typename L2::orientation_category orientation_category;
  279. if (init)
  280. v.assign (zero_vector<value_type> (e2.size2 ()));
  281. #if BOOST_UBLAS_TYPE_CHECK
  282. vector<value_type> cv (v);
  283. typedef typename type_traits<value_type>::real_type real_type;
  284. real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
  285. indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
  286. #endif
  287. axpy_prod (e1, e2, v, orientation_category ());
  288. #if BOOST_UBLAS_TYPE_CHECK
  289. BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
  290. #endif
  291. return v;
  292. }
  293. template<class V, class E1, class T2, class L2, class IA2, class TA2>
  294. BOOST_UBLAS_INLINE
  295. V
  296. axpy_prod (const vector_expression<E1> &e1,
  297. const compressed_matrix<T2, L2, 0, IA2, TA2> &e2) {
  298. typedef V vector_type;
  299. vector_type v (e2.size2 ());
  300. return axpy_prod (e1, e2, v, true);
  301. }
  302. template<class V, class E1, class E2>
  303. BOOST_UBLAS_INLINE
  304. V &
  305. axpy_prod (const vector_expression<E1> &e1,
  306. const matrix_expression<E2> &e2,
  307. V &v, packed_random_access_iterator_tag, column_major_tag) {
  308. typedef const E2 expression2_type;
  309. typedef typename V::size_type size_type;
  310. typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
  311. typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
  312. while (it2 != it2_end) {
  313. size_type index2 (it2.index2 ());
  314. #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  315. typename expression2_type::const_iterator1 it1 (it2.begin ());
  316. typename expression2_type::const_iterator1 it1_end (it2.end ());
  317. #else
  318. typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
  319. typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
  320. #endif
  321. while (it1 != it1_end) {
  322. v (index2) += *it1 * e1 () (it1.index1 ());
  323. ++ it1;
  324. }
  325. ++ it2;
  326. }
  327. return v;
  328. }
  329. template<class V, class E1, class E2>
  330. BOOST_UBLAS_INLINE
  331. V &
  332. axpy_prod (const vector_expression<E1> &e1,
  333. const matrix_expression<E2> &e2,
  334. V &v, packed_random_access_iterator_tag, row_major_tag) {
  335. typedef const E2 expression2_type;
  336. typedef typename V::size_type size_type;
  337. typename expression2_type::const_iterator1 it1 (e2 ().begin1 ());
  338. typename expression2_type::const_iterator1 it1_end (e2 ().end1 ());
  339. while (it1 != it1_end) {
  340. size_type index1 (it1.index1 ());
  341. #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  342. typename expression2_type::const_iterator2 it2 (it1.begin ());
  343. typename expression2_type::const_iterator2 it2_end (it1.end ());
  344. #else
  345. typename expression2_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
  346. typename expression2_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
  347. #endif
  348. while (it2 != it2_end) {
  349. v (it2.index2 ()) += *it2 * e1 () (index1);
  350. ++ it2;
  351. }
  352. ++ it1;
  353. }
  354. return v;
  355. }
  356. template<class V, class E1, class E2>
  357. BOOST_UBLAS_INLINE
  358. V &
  359. axpy_prod (const vector_expression<E1> &e1,
  360. const matrix_expression<E2> &e2,
  361. V &v, sparse_bidirectional_iterator_tag) {
  362. typedef const E1 expression1_type;
  363. typename expression1_type::const_iterator it (e1 ().begin ());
  364. typename expression1_type::const_iterator it_end (e1 ().end ());
  365. while (it != it_end) {
  366. v.plus_assign (*it * row (e2 (), it.index ()));
  367. ++ it;
  368. }
  369. return v;
  370. }
  371. // Dispatcher
  372. template<class V, class E1, class E2>
  373. BOOST_UBLAS_INLINE
  374. V &
  375. axpy_prod (const vector_expression<E1> &e1,
  376. const matrix_expression<E2> &e2,
  377. V &v, packed_random_access_iterator_tag) {
  378. typedef typename E2::orientation_category orientation_category;
  379. return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
  380. }
  381. /** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
  382. optimized fashion.
  383. \param e1 the vector expression \c x
  384. \param e2 the matrix expression \c A
  385. \param v the result vector \c v
  386. \param init a boolean parameter
  387. <tt>axpy_prod(x, A, v, init)</tt> implements the well known
  388. axpy-product. Setting \a init to \c true is equivalent to call
  389. <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
  390. defaults to \c true, but this may change in the future.
  391. Up to now there are some specialisation for compressed
  392. matrices that give a large speed up compared to prod.
  393. \ingroup blas2
  394. \internal
  395. template parameters:
  396. \param V type of the result vector \c v
  397. \param E1 type of a vector expression \c x
  398. \param E2 type of a matrix expression \c A
  399. */
  400. template<class V, class E1, class E2>
  401. BOOST_UBLAS_INLINE
  402. V &
  403. axpy_prod (const vector_expression<E1> &e1,
  404. const matrix_expression<E2> &e2,
  405. V &v, bool init = true) {
  406. typedef typename V::value_type value_type;
  407. typedef typename E1::const_iterator::iterator_category iterator_category;
  408. if (init)
  409. v.assign (zero_vector<value_type> (e2 ().size2 ()));
  410. #if BOOST_UBLAS_TYPE_CHECK
  411. vector<value_type> cv (v);
  412. typedef typename type_traits<value_type>::real_type real_type;
  413. real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
  414. indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
  415. #endif
  416. axpy_prod (e1, e2, v, iterator_category ());
  417. #if BOOST_UBLAS_TYPE_CHECK
  418. BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
  419. #endif
  420. return v;
  421. }
  422. template<class V, class E1, class E2>
  423. BOOST_UBLAS_INLINE
  424. V
  425. axpy_prod (const vector_expression<E1> &e1,
  426. const matrix_expression<E2> &e2) {
  427. typedef V vector_type;
  428. vector_type v (e2 ().size2 ());
  429. return axpy_prod (e1, e2, v, true);
  430. }
  431. template<class M, class E1, class E2, class TRI>
  432. BOOST_UBLAS_INLINE
  433. M &
  434. axpy_prod (const matrix_expression<E1> &e1,
  435. const matrix_expression<E2> &e2,
  436. M &m, TRI,
  437. dense_proxy_tag, row_major_tag) {
  438. typedef typename M::size_type size_type;
  439. #if BOOST_UBLAS_TYPE_CHECK
  440. typedef typename M::value_type value_type;
  441. matrix<value_type, row_major> cm (m);
  442. typedef typename type_traits<value_type>::real_type real_type;
  443. real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
  444. indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
  445. #endif
  446. size_type size1 (e1 ().size1 ());
  447. size_type size2 (e1 ().size2 ());
  448. for (size_type i = 0; i < size1; ++ i)
  449. for (size_type j = 0; j < size2; ++ j)
  450. row (m, i).plus_assign (e1 () (i, j) * row (e2 (), j));
  451. #if BOOST_UBLAS_TYPE_CHECK
  452. BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
  453. #endif
  454. return m;
  455. }
  456. template<class M, class E1, class E2, class TRI>
  457. BOOST_UBLAS_INLINE
  458. M &
  459. axpy_prod (const matrix_expression<E1> &e1,
  460. const matrix_expression<E2> &e2,
  461. M &m, TRI,
  462. sparse_proxy_tag, row_major_tag) {
  463. typedef TRI triangular_restriction;
  464. typedef const E1 expression1_type;
  465. typedef const E2 expression2_type;
  466. #if BOOST_UBLAS_TYPE_CHECK
  467. typedef typename M::value_type value_type;
  468. matrix<value_type, row_major> cm (m);
  469. typedef typename type_traits<value_type>::real_type real_type;
  470. real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
  471. indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
  472. #endif
  473. typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
  474. typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
  475. while (it1 != it1_end) {
  476. #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  477. typename expression1_type::const_iterator2 it2 (it1.begin ());
  478. typename expression1_type::const_iterator2 it2_end (it1.end ());
  479. #else
  480. typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
  481. typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
  482. #endif
  483. while (it2 != it2_end) {
  484. // row (m, it1.index1 ()).plus_assign (*it2 * row (e2 (), it2.index2 ()));
  485. matrix_row<expression2_type> mr (e2 (), it2.index2 ());
  486. typename matrix_row<expression2_type>::const_iterator itr (mr.begin ());
  487. typename matrix_row<expression2_type>::const_iterator itr_end (mr.end ());
  488. while (itr != itr_end) {
  489. if (triangular_restriction::other (it1.index1 (), itr.index ()))
  490. m (it1.index1 (), itr.index ()) += *it2 * *itr;
  491. ++ itr;
  492. }
  493. ++ it2;
  494. }
  495. ++ it1;
  496. }
  497. #if BOOST_UBLAS_TYPE_CHECK
  498. BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
  499. #endif
  500. return m;
  501. }
  502. template<class M, class E1, class E2, class TRI>
  503. BOOST_UBLAS_INLINE
  504. M &
  505. axpy_prod (const matrix_expression<E1> &e1,
  506. const matrix_expression<E2> &e2,
  507. M &m, TRI,
  508. dense_proxy_tag, column_major_tag) {
  509. typedef typename M::size_type size_type;
  510. #if BOOST_UBLAS_TYPE_CHECK
  511. typedef typename M::value_type value_type;
  512. matrix<value_type, column_major> cm (m);
  513. typedef typename type_traits<value_type>::real_type real_type;
  514. real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
  515. indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
  516. #endif
  517. size_type size1 (e2 ().size1 ());
  518. size_type size2 (e2 ().size2 ());
  519. for (size_type j = 0; j < size2; ++ j)
  520. for (size_type i = 0; i < size1; ++ i)
  521. column (m, j).plus_assign (e2 () (i, j) * column (e1 (), i));
  522. #if BOOST_UBLAS_TYPE_CHECK
  523. BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
  524. #endif
  525. return m;
  526. }
  527. template<class M, class E1, class E2, class TRI>
  528. BOOST_UBLAS_INLINE
  529. M &
  530. axpy_prod (const matrix_expression<E1> &e1,
  531. const matrix_expression<E2> &e2,
  532. M &m, TRI,
  533. sparse_proxy_tag, column_major_tag) {
  534. typedef TRI triangular_restriction;
  535. typedef const E1 expression1_type;
  536. typedef const E2 expression2_type;
  537. #if BOOST_UBLAS_TYPE_CHECK
  538. typedef typename M::value_type value_type;
  539. matrix<value_type, column_major> cm (m);
  540. typedef typename type_traits<value_type>::real_type real_type;
  541. real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
  542. indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
  543. #endif
  544. typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
  545. typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
  546. while (it2 != it2_end) {
  547. #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  548. typename expression2_type::const_iterator1 it1 (it2.begin ());
  549. typename expression2_type::const_iterator1 it1_end (it2.end ());
  550. #else
  551. typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
  552. typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
  553. #endif
  554. while (it1 != it1_end) {
  555. // column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
  556. matrix_column<expression1_type> mc (e1 (), it1.index1 ());
  557. typename matrix_column<expression1_type>::const_iterator itc (mc.begin ());
  558. typename matrix_column<expression1_type>::const_iterator itc_end (mc.end ());
  559. while (itc != itc_end) {
  560. if(triangular_restriction::other (itc.index (), it2.index2 ()))
  561. m (itc.index (), it2.index2 ()) += *it1 * *itc;
  562. ++ itc;
  563. }
  564. ++ it1;
  565. }
  566. ++ it2;
  567. }
  568. #if BOOST_UBLAS_TYPE_CHECK
  569. BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
  570. #endif
  571. return m;
  572. }
  573. // Dispatcher
  574. template<class M, class E1, class E2, class TRI>
  575. BOOST_UBLAS_INLINE
  576. M &
  577. axpy_prod (const matrix_expression<E1> &e1,
  578. const matrix_expression<E2> &e2,
  579. M &m, TRI, bool init = true) {
  580. typedef typename M::value_type value_type;
  581. typedef typename M::storage_category storage_category;
  582. typedef typename M::orientation_category orientation_category;
  583. typedef TRI triangular_restriction;
  584. if (init)
  585. m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
  586. return axpy_prod (e1, e2, m, triangular_restriction (), storage_category (), orientation_category ());
  587. }
  588. template<class M, class E1, class E2, class TRI>
  589. BOOST_UBLAS_INLINE
  590. M
  591. axpy_prod (const matrix_expression<E1> &e1,
  592. const matrix_expression<E2> &e2,
  593. TRI) {
  594. typedef M matrix_type;
  595. typedef TRI triangular_restriction;
  596. matrix_type m (e1 ().size1 (), e2 ().size2 ());
  597. return axpy_prod (e1, e2, m, triangular_restriction (), true);
  598. }
  599. /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
  600. optimized fashion.
  601. \param e1 the matrix expression \c A
  602. \param e2 the matrix expression \c X
  603. \param m the result matrix \c M
  604. \param init a boolean parameter
  605. <tt>axpy_prod(A, X, M, init)</tt> implements the well known
  606. axpy-product. Setting \a init to \c true is equivalent to call
  607. <tt>M.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
  608. defaults to \c true, but this may change in the future.
  609. Up to now there are no specialisations.
  610. \ingroup blas3
  611. \internal
  612. template parameters:
  613. \param M type of the result matrix \c M
  614. \param E1 type of a matrix expression \c A
  615. \param E2 type of a matrix expression \c X
  616. */
  617. template<class M, class E1, class E2>
  618. BOOST_UBLAS_INLINE
  619. M &
  620. axpy_prod (const matrix_expression<E1> &e1,
  621. const matrix_expression<E2> &e2,
  622. M &m, bool init = true) {
  623. typedef typename M::value_type value_type;
  624. typedef typename M::storage_category storage_category;
  625. typedef typename M::orientation_category orientation_category;
  626. if (init)
  627. m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
  628. return axpy_prod (e1, e2, m, full (), storage_category (), orientation_category ());
  629. }
  630. template<class M, class E1, class E2>
  631. BOOST_UBLAS_INLINE
  632. M
  633. axpy_prod (const matrix_expression<E1> &e1,
  634. const matrix_expression<E2> &e2) {
  635. typedef M matrix_type;
  636. matrix_type m (e1 ().size1 (), e2 ().size2 ());
  637. return axpy_prod (e1, e2, m, full (), true);
  638. }
  639. template<class M, class E1, class E2>
  640. BOOST_UBLAS_INLINE
  641. M &
  642. opb_prod (const matrix_expression<E1> &e1,
  643. const matrix_expression<E2> &e2,
  644. M &m,
  645. dense_proxy_tag, row_major_tag) {
  646. typedef typename M::size_type size_type;
  647. typedef typename M::value_type value_type;
  648. #if BOOST_UBLAS_TYPE_CHECK
  649. matrix<value_type, row_major> cm (m);
  650. typedef typename type_traits<value_type>::real_type real_type;
  651. real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
  652. indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
  653. #endif
  654. size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
  655. for (size_type k = 0; k < size; ++ k) {
  656. vector<value_type> ce1 (column (e1 (), k));
  657. vector<value_type> re2 (row (e2 (), k));
  658. m.plus_assign (outer_prod (ce1, re2));
  659. }
  660. #if BOOST_UBLAS_TYPE_CHECK
  661. BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
  662. #endif
  663. return m;
  664. }
  665. template<class M, class E1, class E2>
  666. BOOST_UBLAS_INLINE
  667. M &
  668. opb_prod (const matrix_expression<E1> &e1,
  669. const matrix_expression<E2> &e2,
  670. M &m,
  671. dense_proxy_tag, column_major_tag) {
  672. typedef typename M::size_type size_type;
  673. typedef typename M::value_type value_type;
  674. #if BOOST_UBLAS_TYPE_CHECK
  675. matrix<value_type, column_major> cm (m);
  676. typedef typename type_traits<value_type>::real_type real_type;
  677. real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
  678. indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
  679. #endif
  680. size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
  681. for (size_type k = 0; k < size; ++ k) {
  682. vector<value_type> ce1 (column (e1 (), k));
  683. vector<value_type> re2 (row (e2 (), k));
  684. m.plus_assign (outer_prod (ce1, re2));
  685. }
  686. #if BOOST_UBLAS_TYPE_CHECK
  687. BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
  688. #endif
  689. return m;
  690. }
  691. // Dispatcher
  692. /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
  693. optimized fashion.
  694. \param e1 the matrix expression \c A
  695. \param e2 the matrix expression \c X
  696. \param m the result matrix \c M
  697. \param init a boolean parameter
  698. <tt>opb_prod(A, X, M, init)</tt> implements the well known
  699. axpy-product. Setting \a init to \c true is equivalent to call
  700. <tt>M.clear()</tt> before <tt>opb_prod</tt>. Currently \a init
  701. defaults to \c true, but this may change in the future.
  702. This function may give a speedup if \c A has less columns than
  703. rows, because the product is computed as a sum of outer
  704. products.
  705. \ingroup blas3
  706. \internal
  707. template parameters:
  708. \param M type of the result matrix \c M
  709. \param E1 type of a matrix expression \c A
  710. \param E2 type of a matrix expression \c X
  711. */
  712. template<class M, class E1, class E2>
  713. BOOST_UBLAS_INLINE
  714. M &
  715. opb_prod (const matrix_expression<E1> &e1,
  716. const matrix_expression<E2> &e2,
  717. M &m, bool init = true) {
  718. typedef typename M::value_type value_type;
  719. typedef typename M::storage_category storage_category;
  720. typedef typename M::orientation_category orientation_category;
  721. if (init)
  722. m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
  723. return opb_prod (e1, e2, m, storage_category (), orientation_category ());
  724. }
  725. template<class M, class E1, class E2>
  726. BOOST_UBLAS_INLINE
  727. M
  728. opb_prod (const matrix_expression<E1> &e1,
  729. const matrix_expression<E2> &e2) {
  730. typedef M matrix_type;
  731. matrix_type m (e1 ().size1 (), e2 ().size2 ());
  732. return opb_prod (e1, e2, m, true);
  733. }
  734. }}}
  735. #endif