First public contribution.
2 // Copyright (c) 2000-2002
3 // Joerg Walter, Mathias Koch
5 // Permission to use, copy, modify, distribute and sell this software
6 // and its documentation for any purpose is hereby granted without fee,
7 // provided that the above copyright notice appear in all copies and
8 // that both that copyright notice and this permission notice appear
9 // in supporting documentation. The authors make no representations
10 // about the suitability of this software for any purpose.
11 // It is provided "as is" without express or implied warranty.
13 // The authors gratefully acknowledge the support of
14 // GeNeSys mbH & Co. KG in producing this work.
17 #ifndef _BOOST_UBLAS_OPERATION_
18 #define _BOOST_UBLAS_OPERATION_
20 #include <boost/numeric/ublas/matrix_proxy.hpp>
22 /** \file operation.hpp
23 * \brief This file contains some specialized products.
26 // axpy-based products
27 // Alexei Novakov had a lot of ideas to improve these. Thanks.
28 // Hendrik Kueck proposed some new kernel. Thanks again.
30 namespace boost { namespace numeric { namespace ublas {
32 template<class V, class T1, class IA1, class TA1, class E2>
35 axpy_prod (const compressed_matrix<T1, row_major, 0, IA1, TA1> &e1,
36 const vector_expression<E2> &e2,
37 V &v, row_major_tag) {
38 typedef typename V::size_type size_type;
39 typedef typename V::value_type value_type;
41 for (size_type i = 0; i < e1.filled1 () -1; ++ i) {
42 size_type begin = e1.index1_data () [i];
43 size_type end = e1.index1_data () [i + 1];
45 for (size_type j = begin; j < end; ++ j)
46 t += e1.value_data () [j] * e2 () (e1.index2_data () [j]);
52 template<class V, class T1, class IA1, class TA1, class E2>
55 axpy_prod (const compressed_matrix<T1, column_major, 0, IA1, TA1> &e1,
56 const vector_expression<E2> &e2,
57 V &v, column_major_tag) {
58 typedef typename V::size_type size_type;
60 for (size_type j = 0; j < e1.filled1 () -1; ++ j) {
61 size_type begin = e1.index1_data () [j];
62 size_type end = e1.index1_data () [j + 1];
63 for (size_type i = begin; i < end; ++ i)
64 v (e1.index2_data () [i]) += e1.value_data () [i] * e2 () (j);
70 template<class V, class T1, class L1, class IA1, class TA1, class E2>
73 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
74 const vector_expression<E2> &e2,
75 V &v, bool init = true) {
76 typedef typename V::value_type value_type;
77 typedef typename L1::orientation_category orientation_category;
80 v.assign (zero_vector<value_type> (e1.size1 ()));
81 #if BOOST_UBLAS_TYPE_CHECK
82 vector<value_type> cv (v);
83 typedef typename type_traits<value_type>::real_type real_type;
84 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
85 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
87 axpy_prod (e1, e2, v, orientation_category ());
88 #if BOOST_UBLAS_TYPE_CHECK
89 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
93 template<class V, class T1, class L1, class IA1, class TA1, class E2>
96 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
97 const vector_expression<E2> &e2) {
98 typedef V vector_type;
100 vector_type v (e1.size1 ());
101 return axpy_prod (e1, e2, v, true);
104 template<class V, class T1, class L1, class IA1, class TA1, class E2>
107 axpy_prod (const coordinate_matrix<T1, L1, 0, IA1, TA1> &e1,
108 const vector_expression<E2> &e2,
109 V &v, bool init = true) {
110 typedef typename V::size_type size_type;
111 typedef typename V::value_type value_type;
112 typedef L1 layout_type;
114 size_type size1 = e1.size1();
115 size_type size2 = e1.size2();
118 noalias(v) = zero_vector<value_type>(size1);
121 for (size_type i = 0; i < e1.nnz(); ++i) {
122 size_type row_index = layout_type::element1( e1.index1_data () [i], size1, e1.index2_data () [i], size2 );
123 size_type col_index = layout_type::element2( e1.index1_data () [i], size1, e1.index2_data () [i], size2 );
124 v( row_index ) += e1.value_data () [i] * e2 () (col_index);
129 template<class V, class E1, class E2>
132 axpy_prod (const matrix_expression<E1> &e1,
133 const vector_expression<E2> &e2,
134 V &v, packed_random_access_iterator_tag, row_major_tag) {
135 typedef const E1 expression1_type;
136 typedef const E2 expression2_type;
137 typedef typename V::size_type size_type;
139 typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
140 typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
141 while (it1 != it1_end) {
142 size_type index1 (it1.index1 ());
143 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
144 typename expression1_type::const_iterator2 it2 (it1.begin ());
145 typename expression1_type::const_iterator2 it2_end (it1.end ());
147 typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
148 typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
150 while (it2 != it2_end) {
151 v (index1) += *it2 * e2 () (it2.index2 ());
159 template<class V, class E1, class E2>
162 axpy_prod (const matrix_expression<E1> &e1,
163 const vector_expression<E2> &e2,
164 V &v, packed_random_access_iterator_tag, column_major_tag) {
165 typedef const E1 expression1_type;
166 typedef const E2 expression2_type;
167 typedef typename V::size_type size_type;
169 typename expression1_type::const_iterator2 it2 (e1 ().begin2 ());
170 typename expression1_type::const_iterator2 it2_end (e1 ().end2 ());
171 while (it2 != it2_end) {
172 size_type index2 (it2.index2 ());
173 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
174 typename expression1_type::const_iterator1 it1 (it2.begin ());
175 typename expression1_type::const_iterator1 it1_end (it2.end ());
177 typename expression1_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
178 typename expression1_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
180 while (it1 != it1_end) {
181 v (it1.index1 ()) += *it1 * e2 () (index2);
189 template<class V, class E1, class E2>
192 axpy_prod (const matrix_expression<E1> &e1,
193 const vector_expression<E2> &e2,
194 V &v, sparse_bidirectional_iterator_tag) {
195 typedef const E1 expression1_type;
196 typedef const E2 expression2_type;
197 typedef typename V::size_type size_type;
199 typename expression2_type::const_iterator it (e2 ().begin ());
200 typename expression2_type::const_iterator it_end (e2 ().end ());
201 while (it != it_end) {
202 v.plus_assign (column (e1 (), it.index ()) * *it);
209 template<class V, class E1, class E2>
212 axpy_prod (const matrix_expression<E1> &e1,
213 const vector_expression<E2> &e2,
214 V &v, packed_random_access_iterator_tag) {
215 typedef typename E1::orientation_category orientation_category;
216 return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
220 /** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
223 \param e1 the matrix expression \c A
224 \param e2 the vector expression \c x
225 \param v the result vector \c v
226 \param init a boolean parameter
228 <tt>axpy_prod(A, x, v, init)</tt> implements the well known
229 axpy-product. Setting \a init to \c true is equivalent to call
230 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
231 defaults to \c true, but this may change in the future.
233 Up to now there are some specialisation for compressed
234 matrices that give a large speed up compared to prod.
241 \param V type of the result vector \c v
242 \param E1 type of a matrix expression \c A
243 \param E2 type of a vector expression \c x
245 template<class V, class E1, class E2>
248 axpy_prod (const matrix_expression<E1> &e1,
249 const vector_expression<E2> &e2,
250 V &v, bool init = true) {
251 typedef typename V::value_type value_type;
252 typedef typename E2::const_iterator::iterator_category iterator_category;
255 v.assign (zero_vector<value_type> (e1 ().size1 ()));
256 #if BOOST_UBLAS_TYPE_CHECK
257 vector<value_type> cv (v);
258 typedef typename type_traits<value_type>::real_type real_type;
259 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
260 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
262 axpy_prod (e1, e2, v, iterator_category ());
263 #if BOOST_UBLAS_TYPE_CHECK
264 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
268 template<class V, class E1, class E2>
271 axpy_prod (const matrix_expression<E1> &e1,
272 const vector_expression<E2> &e2) {
273 typedef V vector_type;
275 vector_type v (e1 ().size1 ());
276 return axpy_prod (e1, e2, v, true);
279 template<class V, class E1, class T2, class IA2, class TA2>
282 axpy_prod (const vector_expression<E1> &e1,
283 const compressed_matrix<T2, column_major, 0, IA2, TA2> &e2,
284 V &v, column_major_tag) {
285 typedef typename V::size_type size_type;
286 typedef typename V::value_type value_type;
288 for (size_type j = 0; j < e2.filled1 () -1; ++ j) {
289 size_type begin = e2.index1_data () [j];
290 size_type end = e2.index1_data () [j + 1];
291 value_type t (v (j));
292 for (size_type i = begin; i < end; ++ i)
293 t += e2.value_data () [i] * e1 () (e2.index2_data () [i]);
299 template<class V, class E1, class T2, class IA2, class TA2>
302 axpy_prod (const vector_expression<E1> &e1,
303 const compressed_matrix<T2, row_major, 0, IA2, TA2> &e2,
304 V &v, row_major_tag) {
305 typedef typename V::size_type size_type;
307 for (size_type i = 0; i < e2.filled1 () -1; ++ i) {
308 size_type begin = e2.index1_data () [i];
309 size_type end = e2.index1_data () [i + 1];
310 for (size_type j = begin; j < end; ++ j)
311 v (e2.index2_data () [j]) += e2.value_data () [j] * e1 () (i);
317 template<class V, class E1, class T2, class L2, class IA2, class TA2>
320 axpy_prod (const vector_expression<E1> &e1,
321 const compressed_matrix<T2, L2, 0, IA2, TA2> &e2,
322 V &v, bool init = true) {
323 typedef typename V::value_type value_type;
324 typedef typename L2::orientation_category orientation_category;
327 v.assign (zero_vector<value_type> (e2.size2 ()));
328 #if BOOST_UBLAS_TYPE_CHECK
329 vector<value_type> cv (v);
330 typedef typename type_traits<value_type>::real_type real_type;
331 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
332 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
334 axpy_prod (e1, e2, v, orientation_category ());
335 #if BOOST_UBLAS_TYPE_CHECK
336 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
340 template<class V, class E1, class T2, class L2, class IA2, class TA2>
343 axpy_prod (const vector_expression<E1> &e1,
344 const compressed_matrix<T2, L2, 0, IA2, TA2> &e2) {
345 typedef V vector_type;
347 vector_type v (e2.size2 ());
348 return axpy_prod (e1, e2, v, true);
351 template<class V, class E1, class E2>
354 axpy_prod (const vector_expression<E1> &e1,
355 const matrix_expression<E2> &e2,
356 V &v, packed_random_access_iterator_tag, column_major_tag) {
357 typedef const E1 expression1_type;
358 typedef const E2 expression2_type;
359 typedef typename V::size_type size_type;
361 typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
362 typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
363 while (it2 != it2_end) {
364 size_type index2 (it2.index2 ());
365 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
366 typename expression2_type::const_iterator1 it1 (it2.begin ());
367 typename expression2_type::const_iterator1 it1_end (it2.end ());
369 typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
370 typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
372 while (it1 != it1_end) {
373 v (index2) += *it1 * e1 () (it1.index1 ());
381 template<class V, class E1, class E2>
384 axpy_prod (const vector_expression<E1> &e1,
385 const matrix_expression<E2> &e2,
386 V &v, packed_random_access_iterator_tag, row_major_tag) {
387 typedef const E1 expression1_type;
388 typedef const E2 expression2_type;
389 typedef typename V::size_type size_type;
391 typename expression2_type::const_iterator1 it1 (e2 ().begin1 ());
392 typename expression2_type::const_iterator1 it1_end (e2 ().end1 ());
393 while (it1 != it1_end) {
394 size_type index1 (it1.index1 ());
395 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
396 typename expression2_type::const_iterator2 it2 (it1.begin ());
397 typename expression2_type::const_iterator2 it2_end (it1.end ());
399 typename expression2_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
400 typename expression2_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
402 while (it2 != it2_end) {
403 v (it2.index2 ()) += *it2 * e1 () (index1);
411 template<class V, class E1, class E2>
414 axpy_prod (const vector_expression<E1> &e1,
415 const matrix_expression<E2> &e2,
416 V &v, sparse_bidirectional_iterator_tag) {
417 typedef const E1 expression1_type;
418 typedef const E2 expression2_type;
419 typedef typename V::size_type size_type;
421 typename expression1_type::const_iterator it (e1 ().begin ());
422 typename expression1_type::const_iterator it_end (e1 ().end ());
423 while (it != it_end) {
424 v.plus_assign (*it * row (e2 (), it.index ()));
431 template<class V, class E1, class E2>
434 axpy_prod (const vector_expression<E1> &e1,
435 const matrix_expression<E2> &e2,
436 V &v, packed_random_access_iterator_tag) {
437 typedef typename E2::orientation_category orientation_category;
438 return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
442 /** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
445 \param e1 the vector expression \c x
446 \param e2 the matrix expression \c A
447 \param v the result vector \c v
448 \param init a boolean parameter
450 <tt>axpy_prod(x, A, v, init)</tt> implements the well known
451 axpy-product. Setting \a init to \c true is equivalent to call
452 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
453 defaults to \c true, but this may change in the future.
455 Up to now there are some specialisation for compressed
456 matrices that give a large speed up compared to prod.
463 \param V type of the result vector \c v
464 \param E1 type of a vector expression \c x
465 \param E2 type of a matrix expression \c A
467 template<class V, class E1, class E2>
470 axpy_prod (const vector_expression<E1> &e1,
471 const matrix_expression<E2> &e2,
472 V &v, bool init = true) {
473 typedef typename V::value_type value_type;
474 typedef typename E1::const_iterator::iterator_category iterator_category;
477 v.assign (zero_vector<value_type> (e2 ().size2 ()));
478 #if BOOST_UBLAS_TYPE_CHECK
479 vector<value_type> cv (v);
480 typedef typename type_traits<value_type>::real_type real_type;
481 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
482 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
484 axpy_prod (e1, e2, v, iterator_category ());
485 #if BOOST_UBLAS_TYPE_CHECK
486 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
490 template<class V, class E1, class E2>
493 axpy_prod (const vector_expression<E1> &e1,
494 const matrix_expression<E2> &e2) {
495 typedef V vector_type;
497 vector_type v (e2 ().size2 ());
498 return axpy_prod (e1, e2, v, true);
501 template<class M, class E1, class E2, class TRI>
504 axpy_prod (const matrix_expression<E1> &e1,
505 const matrix_expression<E2> &e2,
507 dense_proxy_tag, row_major_tag) {
508 typedef M matrix_type;
509 typedef const E1 expression1_type;
510 typedef const E2 expression2_type;
511 typedef typename M::size_type size_type;
512 typedef typename M::value_type value_type;
514 #if BOOST_UBLAS_TYPE_CHECK
515 matrix<value_type, row_major> cm (m);
516 typedef typename type_traits<value_type>::real_type real_type;
517 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
518 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
520 size_type size1 (e1 ().size1 ());
521 size_type size2 (e1 ().size2 ());
522 for (size_type i = 0; i < size1; ++ i)
523 for (size_type j = 0; j < size2; ++ j)
524 row (m, i).plus_assign (e1 () (i, j) * row (e2 (), j));
525 #if BOOST_UBLAS_TYPE_CHECK
526 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
530 template<class M, class E1, class E2, class TRI>
533 axpy_prod (const matrix_expression<E1> &e1,
534 const matrix_expression<E2> &e2,
536 sparse_proxy_tag, row_major_tag) {
537 typedef M matrix_type;
538 typedef TRI triangular_restriction;
539 typedef const E1 expression1_type;
540 typedef const E2 expression2_type;
541 typedef typename M::size_type size_type;
542 typedef typename M::value_type value_type;
544 #if BOOST_UBLAS_TYPE_CHECK
545 matrix<value_type, row_major> cm (m);
546 typedef typename type_traits<value_type>::real_type real_type;
547 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
548 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
550 typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
551 typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
552 while (it1 != it1_end) {
553 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
554 typename expression1_type::const_iterator2 it2 (it1.begin ());
555 typename expression1_type::const_iterator2 it2_end (it1.end ());
557 typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
558 typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
560 while (it2 != it2_end) {
561 // row (m, it1.index1 ()).plus_assign (*it2 * row (e2 (), it2.index2 ()));
562 matrix_row<expression2_type> mr (e2 (), it2.index2 ());
563 typename matrix_row<expression2_type>::const_iterator itr (mr.begin ());
564 typename matrix_row<expression2_type>::const_iterator itr_end (mr.end ());
565 while (itr != itr_end) {
566 if (triangular_restriction::other (it1.index1 (), itr.index ()))
567 m (it1.index1 (), itr.index ()) += *it2 * *itr;
574 #if BOOST_UBLAS_TYPE_CHECK
575 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
580 template<class M, class E1, class E2, class TRI>
583 axpy_prod (const matrix_expression<E1> &e1,
584 const matrix_expression<E2> &e2,
586 dense_proxy_tag, column_major_tag) {
587 typedef M matrix_type;
588 typedef const E1 expression1_type;
589 typedef const E2 expression2_type;
590 typedef typename M::size_type size_type;
591 typedef typename M::value_type value_type;
593 #if BOOST_UBLAS_TYPE_CHECK
594 matrix<value_type, column_major> cm (m);
595 typedef typename type_traits<value_type>::real_type real_type;
596 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
597 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
599 size_type size1 (e2 ().size1 ());
600 size_type size2 (e2 ().size2 ());
601 for (size_type j = 0; j < size2; ++ j)
602 for (size_type i = 0; i < size1; ++ i)
603 column (m, j).plus_assign (e2 () (i, j) * column (e1 (), i));
604 #if BOOST_UBLAS_TYPE_CHECK
605 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
609 template<class M, class E1, class E2, class TRI>
612 axpy_prod (const matrix_expression<E1> &e1,
613 const matrix_expression<E2> &e2,
615 sparse_proxy_tag, column_major_tag) {
616 typedef M matrix_type;
617 typedef TRI triangular_restriction;
618 typedef const E1 expression1_type;
619 typedef const E2 expression2_type;
620 typedef typename M::size_type size_type;
621 typedef typename M::value_type value_type;
623 #if BOOST_UBLAS_TYPE_CHECK
624 matrix<value_type, column_major> cm (m);
625 typedef typename type_traits<value_type>::real_type real_type;
626 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
627 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
629 typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
630 typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
631 while (it2 != it2_end) {
632 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
633 typename expression2_type::const_iterator1 it1 (it2.begin ());
634 typename expression2_type::const_iterator1 it1_end (it2.end ());
636 typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
637 typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
639 while (it1 != it1_end) {
640 // column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
641 matrix_column<expression1_type> mc (e1 (), it1.index1 ());
642 typename matrix_column<expression1_type>::const_iterator itc (mc.begin ());
643 typename matrix_column<expression1_type>::const_iterator itc_end (mc.end ());
644 while (itc != itc_end) {
645 if (triangular_restriction::functor_type ().other (itc.index (), it2.index2 ()))
646 m (itc.index (), it2.index2 ()) += *it1 * *itc;
653 #if BOOST_UBLAS_TYPE_CHECK
654 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
660 template<class M, class E1, class E2, class TRI>
663 axpy_prod (const matrix_expression<E1> &e1,
664 const matrix_expression<E2> &e2,
665 M &m, TRI, bool init = true) {
666 typedef typename M::value_type value_type;
667 typedef typename M::storage_category storage_category;
668 typedef typename M::orientation_category orientation_category;
669 typedef TRI triangular_restriction;
672 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
673 return axpy_prod (e1, e2, m, triangular_restriction (), storage_category (), orientation_category ());
675 template<class M, class E1, class E2, class TRI>
678 axpy_prod (const matrix_expression<E1> &e1,
679 const matrix_expression<E2> &e2,
681 typedef M matrix_type;
682 typedef TRI triangular_restriction;
684 matrix_type m (e1 ().size1 (), e2 ().size2 ());
685 return axpy_prod (e1, e2, m, triangular_restriction (), true);
688 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
691 \param e1 the matrix expression \c A
692 \param e2 the matrix expression \c X
693 \param m the result matrix \c M
694 \param init a boolean parameter
696 <tt>axpy_prod(A, X, M, init)</tt> implements the well known
697 axpy-product. Setting \a init to \c true is equivalent to call
698 <tt>M.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
699 defaults to \c true, but this may change in the future.
701 Up to now there are no specialisations.
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
712 template<class M, class E1, class E2>
715 axpy_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;
723 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
724 return axpy_prod (e1, e2, m, full (), storage_category (), orientation_category ());
726 template<class M, class E1, class E2>
729 axpy_prod (const matrix_expression<E1> &e1,
730 const matrix_expression<E2> &e2) {
731 typedef M matrix_type;
733 matrix_type m (e1 ().size1 (), e2 ().size2 ());
734 return axpy_prod (e1, e2, m, full (), true);
738 template<class M, class E1, class E2>
741 opb_prod (const matrix_expression<E1> &e1,
742 const matrix_expression<E2> &e2,
744 dense_proxy_tag, row_major_tag) {
745 typedef M matrix_type;
746 typedef const E1 expression1_type;
747 typedef const E2 expression2_type;
748 typedef typename M::size_type size_type;
749 typedef typename M::value_type value_type;
751 #if BOOST_UBLAS_TYPE_CHECK
752 matrix<value_type, row_major> cm (m);
753 typedef typename type_traits<value_type>::real_type real_type;
754 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
755 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
757 size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
758 for (size_type k = 0; k < size; ++ k) {
759 vector<value_type> ce1 (column (e1 (), k));
760 vector<value_type> re2 (row (e2 (), k));
761 m.plus_assign (outer_prod (ce1, re2));
763 #if BOOST_UBLAS_TYPE_CHECK
764 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
769 template<class M, class E1, class E2>
772 opb_prod (const matrix_expression<E1> &e1,
773 const matrix_expression<E2> &e2,
775 dense_proxy_tag, column_major_tag) {
776 typedef M matrix_type;
777 typedef const E1 expression1_type;
778 typedef const E2 expression2_type;
779 typedef typename M::size_type size_type;
780 typedef typename M::value_type value_type;
782 #if BOOST_UBLAS_TYPE_CHECK
783 matrix<value_type, column_major> cm (m);
784 typedef typename type_traits<value_type>::real_type real_type;
785 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
786 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
788 size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
789 for (size_type k = 0; k < size; ++ k) {
790 vector<value_type> ce1 (column (e1 (), k));
791 vector<value_type> re2 (row (e2 (), k));
792 m.plus_assign (outer_prod (ce1, re2));
794 #if BOOST_UBLAS_TYPE_CHECK
795 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
802 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
805 \param e1 the matrix expression \c A
806 \param e2 the matrix expression \c X
807 \param m the result matrix \c M
808 \param init a boolean parameter
810 <tt>opb_prod(A, X, M, init)</tt> implements the well known
811 axpy-product. Setting \a init to \c true is equivalent to call
812 <tt>M.clear()</tt> before <tt>opb_prod</tt>. Currently \a init
813 defaults to \c true, but this may change in the future.
815 This function may give a speedup if \c A has less columns than
816 rows, because the product is computed as a sum of outer
824 \param M type of the result matrix \c M
825 \param E1 type of a matrix expression \c A
826 \param E2 type of a matrix expression \c X
828 template<class M, class E1, class E2>
831 opb_prod (const matrix_expression<E1> &e1,
832 const matrix_expression<E2> &e2,
833 M &m, bool init = true) {
834 typedef typename M::value_type value_type;
835 typedef typename M::storage_category storage_category;
836 typedef typename M::orientation_category orientation_category;
839 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
840 return opb_prod (e1, e2, m, storage_category (), orientation_category ());
842 template<class M, class E1, class E2>
845 opb_prod (const matrix_expression<E1> &e1,
846 const matrix_expression<E2> &e2) {
847 typedef M matrix_type;
849 matrix_type m (e1 ().size1 (), e2 ().size2 ());
850 return opb_prod (e1, e2, m, true);