2 // Copyright (c) 2000-2002
3 // Joerg Walter, Mathias Koch
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)
9 // The authors gratefully acknowledge the support of
10 // GeNeSys mbH & Co. KG in producing this work.
13 #ifndef _BOOST_UBLAS_OPERATION_
14 #define _BOOST_UBLAS_OPERATION_
16 #include <boost/numeric/ublas/matrix_proxy.hpp>
18 /** \file operation.hpp
19 * \brief This file contains some specialized products.
22 // axpy-based products
23 // Alexei Novakov had a lot of ideas to improve these. Thanks.
24 // Hendrik Kueck proposed some new kernel. Thanks again.
26 namespace boost { namespace numeric { namespace ublas {
28 template<class V, class T1, class L1, class IA1, class TA1, class E2>
31 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
32 const vector_expression<E2> &e2,
33 V &v, row_major_tag) {
34 typedef typename V::size_type size_type;
35 typedef typename V::value_type value_type;
37 for (size_type i = 0; i < e1.filled1 () -1; ++ i) {
38 size_type begin = e1.index1_data () [i];
39 size_type end = e1.index1_data () [i + 1];
41 for (size_type j = begin; j < end; ++ j)
42 t += e1.value_data () [j] * e2 () (e1.index2_data () [j]);
48 template<class V, class T1, class L1, class IA1, class TA1, class E2>
51 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
52 const vector_expression<E2> &e2,
53 V &v, column_major_tag) {
54 typedef typename V::size_type size_type;
56 for (size_type j = 0; j < e1.filled1 () -1; ++ j) {
57 size_type begin = e1.index1_data () [j];
58 size_type end = e1.index1_data () [j + 1];
59 for (size_type i = begin; i < end; ++ i)
60 v (e1.index2_data () [i]) += e1.value_data () [i] * e2 () (j);
66 template<class V, class T1, class L1, class IA1, class TA1, class E2>
69 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
70 const vector_expression<E2> &e2,
71 V &v, bool init = true) {
72 typedef typename V::value_type value_type;
73 typedef typename L1::orientation_category orientation_category;
76 v.assign (zero_vector<value_type> (e1.size1 ()));
77 #if BOOST_UBLAS_TYPE_CHECK
78 vector<value_type> cv (v);
79 typedef typename type_traits<value_type>::real_type real_type;
80 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
81 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
83 axpy_prod (e1, e2, v, orientation_category ());
84 #if BOOST_UBLAS_TYPE_CHECK
85 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
89 template<class V, class T1, class L1, class IA1, class TA1, class E2>
92 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
93 const vector_expression<E2> &e2) {
94 typedef V vector_type;
96 vector_type v (e1.size1 ());
97 return axpy_prod (e1, e2, v, true);
100 template<class V, class T1, class L1, class IA1, class TA1, class E2>
103 axpy_prod (const coordinate_matrix<T1, L1, 0, IA1, TA1> &e1,
104 const vector_expression<E2> &e2,
105 V &v, bool init = true) {
106 typedef typename V::size_type size_type;
107 typedef typename V::value_type value_type;
108 typedef L1 layout_type;
110 size_type size1 = e1.size1();
111 size_type size2 = e1.size2();
114 noalias(v) = zero_vector<value_type>(size1);
117 for (size_type i = 0; i < e1.nnz(); ++i) {
118 size_type row_index = layout_type::index_M( e1.index1_data () [i], e1.index2_data () [i] );
119 size_type col_index = layout_type::index_m( e1.index1_data () [i], e1.index2_data () [i] );
120 v( row_index ) += e1.value_data () [i] * e2 () (col_index);
125 template<class V, class E1, class E2>
128 axpy_prod (const matrix_expression<E1> &e1,
129 const vector_expression<E2> &e2,
130 V &v, packed_random_access_iterator_tag, row_major_tag) {
131 typedef const E1 expression1_type;
132 typedef typename V::size_type size_type;
134 typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
135 typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
136 while (it1 != it1_end) {
137 size_type index1 (it1.index1 ());
138 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
139 typename expression1_type::const_iterator2 it2 (it1.begin ());
140 typename expression1_type::const_iterator2 it2_end (it1.end ());
142 typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
143 typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
145 while (it2 != it2_end) {
146 v (index1) += *it2 * e2 () (it2.index2 ());
154 template<class V, class E1, class E2>
157 axpy_prod (const matrix_expression<E1> &e1,
158 const vector_expression<E2> &e2,
159 V &v, packed_random_access_iterator_tag, column_major_tag) {
160 typedef const E1 expression1_type;
161 typedef typename V::size_type size_type;
163 typename expression1_type::const_iterator2 it2 (e1 ().begin2 ());
164 typename expression1_type::const_iterator2 it2_end (e1 ().end2 ());
165 while (it2 != it2_end) {
166 size_type index2 (it2.index2 ());
167 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
168 typename expression1_type::const_iterator1 it1 (it2.begin ());
169 typename expression1_type::const_iterator1 it1_end (it2.end ());
171 typename expression1_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
172 typename expression1_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
174 while (it1 != it1_end) {
175 v (it1.index1 ()) += *it1 * e2 () (index2);
183 template<class V, class E1, class E2>
186 axpy_prod (const matrix_expression<E1> &e1,
187 const vector_expression<E2> &e2,
188 V &v, sparse_bidirectional_iterator_tag) {
189 typedef const E2 expression2_type;
191 typename expression2_type::const_iterator it (e2 ().begin ());
192 typename expression2_type::const_iterator it_end (e2 ().end ());
193 while (it != it_end) {
194 v.plus_assign (column (e1 (), it.index ()) * *it);
201 template<class V, class E1, class E2>
204 axpy_prod (const matrix_expression<E1> &e1,
205 const vector_expression<E2> &e2,
206 V &v, packed_random_access_iterator_tag) {
207 typedef typename E1::orientation_category orientation_category;
208 return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
212 /** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
215 \param e1 the matrix expression \c A
216 \param e2 the vector expression \c x
217 \param v the result vector \c v
218 \param init a boolean parameter
220 <tt>axpy_prod(A, x, v, init)</tt> implements the well known
221 axpy-product. Setting \a init to \c true is equivalent to call
222 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
223 defaults to \c true, but this may change in the future.
225 Up to now there are some specialisation for compressed
226 matrices that give a large speed up compared to prod.
233 \param V type of the result vector \c v
234 \param E1 type of a matrix expression \c A
235 \param E2 type of a vector expression \c x
237 template<class V, class E1, class E2>
240 axpy_prod (const matrix_expression<E1> &e1,
241 const vector_expression<E2> &e2,
242 V &v, bool init = true) {
243 typedef typename V::value_type value_type;
244 typedef typename E2::const_iterator::iterator_category iterator_category;
247 v.assign (zero_vector<value_type> (e1 ().size1 ()));
248 #if BOOST_UBLAS_TYPE_CHECK
249 vector<value_type> cv (v);
250 typedef typename type_traits<value_type>::real_type real_type;
251 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
252 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
254 axpy_prod (e1, e2, v, iterator_category ());
255 #if BOOST_UBLAS_TYPE_CHECK
256 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
260 template<class V, class E1, class E2>
263 axpy_prod (const matrix_expression<E1> &e1,
264 const vector_expression<E2> &e2) {
265 typedef V vector_type;
267 vector_type v (e1 ().size1 ());
268 return axpy_prod (e1, e2, v, true);
271 template<class V, class E1, class T2, class IA2, class TA2>
274 axpy_prod (const vector_expression<E1> &e1,
275 const compressed_matrix<T2, column_major, 0, IA2, TA2> &e2,
276 V &v, column_major_tag) {
277 typedef typename V::size_type size_type;
278 typedef typename V::value_type value_type;
280 for (size_type j = 0; j < e2.filled1 () -1; ++ j) {
281 size_type begin = e2.index1_data () [j];
282 size_type end = e2.index1_data () [j + 1];
283 value_type t (v (j));
284 for (size_type i = begin; i < end; ++ i)
285 t += e2.value_data () [i] * e1 () (e2.index2_data () [i]);
291 template<class V, class E1, class T2, class IA2, class TA2>
294 axpy_prod (const vector_expression<E1> &e1,
295 const compressed_matrix<T2, row_major, 0, IA2, TA2> &e2,
296 V &v, row_major_tag) {
297 typedef typename V::size_type size_type;
299 for (size_type i = 0; i < e2.filled1 () -1; ++ i) {
300 size_type begin = e2.index1_data () [i];
301 size_type end = e2.index1_data () [i + 1];
302 for (size_type j = begin; j < end; ++ j)
303 v (e2.index2_data () [j]) += e2.value_data () [j] * e1 () (i);
309 template<class V, class E1, class T2, class L2, class IA2, class TA2>
312 axpy_prod (const vector_expression<E1> &e1,
313 const compressed_matrix<T2, L2, 0, IA2, TA2> &e2,
314 V &v, bool init = true) {
315 typedef typename V::value_type value_type;
316 typedef typename L2::orientation_category orientation_category;
319 v.assign (zero_vector<value_type> (e2.size2 ()));
320 #if BOOST_UBLAS_TYPE_CHECK
321 vector<value_type> cv (v);
322 typedef typename type_traits<value_type>::real_type real_type;
323 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
324 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
326 axpy_prod (e1, e2, v, orientation_category ());
327 #if BOOST_UBLAS_TYPE_CHECK
328 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
332 template<class V, class E1, class T2, class L2, class IA2, class TA2>
335 axpy_prod (const vector_expression<E1> &e1,
336 const compressed_matrix<T2, L2, 0, IA2, TA2> &e2) {
337 typedef V vector_type;
339 vector_type v (e2.size2 ());
340 return axpy_prod (e1, e2, v, true);
343 template<class V, class E1, class E2>
346 axpy_prod (const vector_expression<E1> &e1,
347 const matrix_expression<E2> &e2,
348 V &v, packed_random_access_iterator_tag, column_major_tag) {
349 typedef const E2 expression2_type;
350 typedef typename V::size_type size_type;
352 typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
353 typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
354 while (it2 != it2_end) {
355 size_type index2 (it2.index2 ());
356 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
357 typename expression2_type::const_iterator1 it1 (it2.begin ());
358 typename expression2_type::const_iterator1 it1_end (it2.end ());
360 typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
361 typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
363 while (it1 != it1_end) {
364 v (index2) += *it1 * e1 () (it1.index1 ());
372 template<class V, class E1, class E2>
375 axpy_prod (const vector_expression<E1> &e1,
376 const matrix_expression<E2> &e2,
377 V &v, packed_random_access_iterator_tag, row_major_tag) {
378 typedef const E2 expression2_type;
379 typedef typename V::size_type size_type;
381 typename expression2_type::const_iterator1 it1 (e2 ().begin1 ());
382 typename expression2_type::const_iterator1 it1_end (e2 ().end1 ());
383 while (it1 != it1_end) {
384 size_type index1 (it1.index1 ());
385 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
386 typename expression2_type::const_iterator2 it2 (it1.begin ());
387 typename expression2_type::const_iterator2 it2_end (it1.end ());
389 typename expression2_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
390 typename expression2_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
392 while (it2 != it2_end) {
393 v (it2.index2 ()) += *it2 * e1 () (index1);
401 template<class V, class E1, class E2>
404 axpy_prod (const vector_expression<E1> &e1,
405 const matrix_expression<E2> &e2,
406 V &v, sparse_bidirectional_iterator_tag) {
407 typedef const E1 expression1_type;
409 typename expression1_type::const_iterator it (e1 ().begin ());
410 typename expression1_type::const_iterator it_end (e1 ().end ());
411 while (it != it_end) {
412 v.plus_assign (*it * row (e2 (), it.index ()));
419 template<class V, class E1, class E2>
422 axpy_prod (const vector_expression<E1> &e1,
423 const matrix_expression<E2> &e2,
424 V &v, packed_random_access_iterator_tag) {
425 typedef typename E2::orientation_category orientation_category;
426 return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
430 /** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
433 \param e1 the vector expression \c x
434 \param e2 the matrix expression \c A
435 \param v the result vector \c v
436 \param init a boolean parameter
438 <tt>axpy_prod(x, A, v, init)</tt> implements the well known
439 axpy-product. Setting \a init to \c true is equivalent to call
440 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
441 defaults to \c true, but this may change in the future.
443 Up to now there are some specialisation for compressed
444 matrices that give a large speed up compared to prod.
451 \param V type of the result vector \c v
452 \param E1 type of a vector expression \c x
453 \param E2 type of a matrix expression \c A
455 template<class V, class E1, class E2>
458 axpy_prod (const vector_expression<E1> &e1,
459 const matrix_expression<E2> &e2,
460 V &v, bool init = true) {
461 typedef typename V::value_type value_type;
462 typedef typename E1::const_iterator::iterator_category iterator_category;
465 v.assign (zero_vector<value_type> (e2 ().size2 ()));
466 #if BOOST_UBLAS_TYPE_CHECK
467 vector<value_type> cv (v);
468 typedef typename type_traits<value_type>::real_type real_type;
469 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
470 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
472 axpy_prod (e1, e2, v, iterator_category ());
473 #if BOOST_UBLAS_TYPE_CHECK
474 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
478 template<class V, class E1, class E2>
481 axpy_prod (const vector_expression<E1> &e1,
482 const matrix_expression<E2> &e2) {
483 typedef V vector_type;
485 vector_type v (e2 ().size2 ());
486 return axpy_prod (e1, e2, v, true);
489 template<class M, class E1, class E2, class TRI>
492 axpy_prod (const matrix_expression<E1> &e1,
493 const matrix_expression<E2> &e2,
495 dense_proxy_tag, row_major_tag) {
497 typedef typename M::size_type size_type;
499 #if BOOST_UBLAS_TYPE_CHECK
500 typedef typename M::value_type value_type;
501 matrix<value_type, row_major> cm (m);
502 typedef typename type_traits<value_type>::real_type real_type;
503 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
504 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
506 size_type size1 (e1 ().size1 ());
507 size_type size2 (e1 ().size2 ());
508 for (size_type i = 0; i < size1; ++ i)
509 for (size_type j = 0; j < size2; ++ j)
510 row (m, i).plus_assign (e1 () (i, j) * row (e2 (), j));
511 #if BOOST_UBLAS_TYPE_CHECK
512 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
516 template<class M, class E1, class E2, class TRI>
519 axpy_prod (const matrix_expression<E1> &e1,
520 const matrix_expression<E2> &e2,
522 sparse_proxy_tag, row_major_tag) {
524 typedef TRI triangular_restriction;
525 typedef const E1 expression1_type;
526 typedef const E2 expression2_type;
528 #if BOOST_UBLAS_TYPE_CHECK
529 typedef typename M::value_type value_type;
530 matrix<value_type, row_major> cm (m);
531 typedef typename type_traits<value_type>::real_type real_type;
532 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
533 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
535 typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
536 typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
537 while (it1 != it1_end) {
538 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
539 typename expression1_type::const_iterator2 it2 (it1.begin ());
540 typename expression1_type::const_iterator2 it2_end (it1.end ());
542 typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
543 typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
545 while (it2 != it2_end) {
546 // row (m, it1.index1 ()).plus_assign (*it2 * row (e2 (), it2.index2 ()));
547 matrix_row<expression2_type> mr (e2 (), it2.index2 ());
548 typename matrix_row<expression2_type>::const_iterator itr (mr.begin ());
549 typename matrix_row<expression2_type>::const_iterator itr_end (mr.end ());
550 while (itr != itr_end) {
551 if (triangular_restriction::other (it1.index1 (), itr.index ()))
552 m (it1.index1 (), itr.index ()) += *it2 * *itr;
559 #if BOOST_UBLAS_TYPE_CHECK
560 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
565 template<class M, class E1, class E2, class TRI>
568 axpy_prod (const matrix_expression<E1> &e1,
569 const matrix_expression<E2> &e2,
571 dense_proxy_tag, column_major_tag) {
572 typedef typename M::size_type size_type;
574 #if BOOST_UBLAS_TYPE_CHECK
575 typedef typename M::value_type value_type;
576 matrix<value_type, column_major> cm (m);
577 typedef typename type_traits<value_type>::real_type real_type;
578 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
579 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
581 size_type size1 (e2 ().size1 ());
582 size_type size2 (e2 ().size2 ());
583 for (size_type j = 0; j < size2; ++ j)
584 for (size_type i = 0; i < size1; ++ i)
585 column (m, j).plus_assign (e2 () (i, j) * column (e1 (), i));
586 #if BOOST_UBLAS_TYPE_CHECK
587 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
591 template<class M, class E1, class E2, class TRI>
594 axpy_prod (const matrix_expression<E1> &e1,
595 const matrix_expression<E2> &e2,
597 sparse_proxy_tag, column_major_tag) {
598 typedef TRI triangular_restriction;
599 typedef const E1 expression1_type;
600 typedef const E2 expression2_type;
603 #if BOOST_UBLAS_TYPE_CHECK
604 typedef typename M::value_type value_type;
605 matrix<value_type, column_major> cm (m);
606 typedef typename type_traits<value_type>::real_type real_type;
607 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
608 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
610 typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
611 typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
612 while (it2 != it2_end) {
613 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
614 typename expression2_type::const_iterator1 it1 (it2.begin ());
615 typename expression2_type::const_iterator1 it1_end (it2.end ());
617 typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
618 typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
620 while (it1 != it1_end) {
621 // column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
622 matrix_column<expression1_type> mc (e1 (), it1.index1 ());
623 typename matrix_column<expression1_type>::const_iterator itc (mc.begin ());
624 typename matrix_column<expression1_type>::const_iterator itc_end (mc.end ());
625 while (itc != itc_end) {
626 if(triangular_restriction::other (itc.index (), it2.index2 ()))
627 m (itc.index (), it2.index2 ()) += *it1 * *itc;
634 #if BOOST_UBLAS_TYPE_CHECK
635 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
641 template<class M, class E1, class E2, class TRI>
644 axpy_prod (const matrix_expression<E1> &e1,
645 const matrix_expression<E2> &e2,
646 M &m, TRI, bool init = true) {
647 typedef typename M::value_type value_type;
648 typedef typename M::storage_category storage_category;
649 typedef typename M::orientation_category orientation_category;
650 typedef TRI triangular_restriction;
653 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
654 return axpy_prod (e1, e2, m, triangular_restriction (), storage_category (), orientation_category ());
656 template<class M, class E1, class E2, class TRI>
659 axpy_prod (const matrix_expression<E1> &e1,
660 const matrix_expression<E2> &e2,
662 typedef M matrix_type;
663 typedef TRI triangular_restriction;
665 matrix_type m (e1 ().size1 (), e2 ().size2 ());
666 return axpy_prod (e1, e2, m, triangular_restriction (), true);
669 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
672 \param e1 the matrix expression \c A
673 \param e2 the matrix expression \c X
674 \param m the result matrix \c M
675 \param init a boolean parameter
677 <tt>axpy_prod(A, X, M, init)</tt> implements the well known
678 axpy-product. Setting \a init to \c true is equivalent to call
679 <tt>M.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
680 defaults to \c true, but this may change in the future.
682 Up to now there are no specialisations.
689 \param M type of the result matrix \c M
690 \param E1 type of a matrix expression \c A
691 \param E2 type of a matrix expression \c X
693 template<class M, class E1, class E2>
696 axpy_prod (const matrix_expression<E1> &e1,
697 const matrix_expression<E2> &e2,
698 M &m, bool init = true) {
699 typedef typename M::value_type value_type;
700 typedef typename M::storage_category storage_category;
701 typedef typename M::orientation_category orientation_category;
704 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
705 return axpy_prod (e1, e2, m, full (), storage_category (), orientation_category ());
707 template<class M, class E1, class E2>
710 axpy_prod (const matrix_expression<E1> &e1,
711 const matrix_expression<E2> &e2) {
712 typedef M matrix_type;
714 matrix_type m (e1 ().size1 (), e2 ().size2 ());
715 return axpy_prod (e1, e2, m, full (), true);
719 template<class M, class E1, class E2>
722 opb_prod (const matrix_expression<E1> &e1,
723 const matrix_expression<E2> &e2,
725 dense_proxy_tag, row_major_tag) {
726 typedef typename M::size_type size_type;
727 typedef typename M::value_type value_type;
729 #if BOOST_UBLAS_TYPE_CHECK
730 matrix<value_type, row_major> cm (m);
731 typedef typename type_traits<value_type>::real_type real_type;
732 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
733 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
735 size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
736 for (size_type k = 0; k < size; ++ k) {
737 vector<value_type> ce1 (column (e1 (), k));
738 vector<value_type> re2 (row (e2 (), k));
739 m.plus_assign (outer_prod (ce1, re2));
741 #if BOOST_UBLAS_TYPE_CHECK
742 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
747 template<class M, class E1, class E2>
750 opb_prod (const matrix_expression<E1> &e1,
751 const matrix_expression<E2> &e2,
753 dense_proxy_tag, column_major_tag) {
754 typedef typename M::size_type size_type;
755 typedef typename M::value_type value_type;
757 #if BOOST_UBLAS_TYPE_CHECK
758 matrix<value_type, column_major> cm (m);
759 typedef typename type_traits<value_type>::real_type real_type;
760 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
761 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
763 size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
764 for (size_type k = 0; k < size; ++ k) {
765 vector<value_type> ce1 (column (e1 (), k));
766 vector<value_type> re2 (row (e2 (), k));
767 m.plus_assign (outer_prod (ce1, re2));
769 #if BOOST_UBLAS_TYPE_CHECK
770 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
777 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
780 \param e1 the matrix expression \c A
781 \param e2 the matrix expression \c X
782 \param m the result matrix \c M
783 \param init a boolean parameter
785 <tt>opb_prod(A, X, M, init)</tt> implements the well known
786 axpy-product. Setting \a init to \c true is equivalent to call
787 <tt>M.clear()</tt> before <tt>opb_prod</tt>. Currently \a init
788 defaults to \c true, but this may change in the future.
790 This function may give a speedup if \c A has less columns than
791 rows, because the product is computed as a sum of outer
799 \param M type of the result matrix \c M
800 \param E1 type of a matrix expression \c A
801 \param E2 type of a matrix expression \c X
803 template<class M, class E1, class E2>
806 opb_prod (const matrix_expression<E1> &e1,
807 const matrix_expression<E2> &e2,
808 M &m, bool init = true) {
809 typedef typename M::value_type value_type;
810 typedef typename M::storage_category storage_category;
811 typedef typename M::orientation_category orientation_category;
814 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
815 return opb_prod (e1, e2, m, storage_category (), orientation_category ());
817 template<class M, class E1, class E2>
820 opb_prod (const matrix_expression<E1> &e1,
821 const matrix_expression<E2> &e2) {
822 typedef M matrix_type;
824 matrix_type m (e1 ().size1 (), e2 ().size2 ());
825 return opb_prod (e1, e2, m, true);