operation.hpp 32 KB

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