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 const E2 expression2_type
;
133 typedef typename
V::size_type size_type
;
135 typename
expression1_type::const_iterator1
it1 (e1 ().begin1 ());
136 typename
expression1_type::const_iterator1
it1_end (e1 ().end1 ());
137 while (it1
!= it1_end
) {
138 size_type
index1 (it1
.index1 ());
139 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
140 typename
expression1_type::const_iterator2
it2 (it1
.begin ());
141 typename
expression1_type::const_iterator2
it2_end (it1
.end ());
143 typename
expression1_type::const_iterator2
it2 (boost::numeric::ublas::begin (it1
, iterator1_tag ()));
144 typename
expression1_type::const_iterator2
it2_end (boost::numeric::ublas::end (it1
, iterator1_tag ()));
146 while (it2
!= it2_end
) {
147 v (index1
) += *it2
* e2 () (it2
.index2 ());
155 template<class V
, class E1
, class E2
>
158 axpy_prod (const matrix_expression
<E1
> &e1
,
159 const vector_expression
<E2
> &e2
,
160 V
&v
, packed_random_access_iterator_tag
, column_major_tag
) {
161 typedef const E1 expression1_type
;
162 typedef const E2 expression2_type
;
163 typedef typename
V::size_type size_type
;
165 typename
expression1_type::const_iterator2
it2 (e1 ().begin2 ());
166 typename
expression1_type::const_iterator2
it2_end (e1 ().end2 ());
167 while (it2
!= it2_end
) {
168 size_type
index2 (it2
.index2 ());
169 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
170 typename
expression1_type::const_iterator1
it1 (it2
.begin ());
171 typename
expression1_type::const_iterator1
it1_end (it2
.end ());
173 typename
expression1_type::const_iterator1
it1 (boost::numeric::ublas::begin (it2
, iterator2_tag ()));
174 typename
expression1_type::const_iterator1
it1_end (boost::numeric::ublas::end (it2
, iterator2_tag ()));
176 while (it1
!= it1_end
) {
177 v (it1
.index1 ()) += *it1
* e2 () (index2
);
185 template<class V
, class E1
, class E2
>
188 axpy_prod (const matrix_expression
<E1
> &e1
,
189 const vector_expression
<E2
> &e2
,
190 V
&v
, sparse_bidirectional_iterator_tag
) {
191 typedef const E1 expression1_type
;
192 typedef const E2 expression2_type
;
193 typedef typename
V::size_type size_type
;
195 typename
expression2_type::const_iterator
it (e2 ().begin ());
196 typename
expression2_type::const_iterator
it_end (e2 ().end ());
197 while (it
!= it_end
) {
198 v
.plus_assign (column (e1 (), it
.index ()) * *it
);
205 template<class V
, class E1
, class E2
>
208 axpy_prod (const matrix_expression
<E1
> &e1
,
209 const vector_expression
<E2
> &e2
,
210 V
&v
, packed_random_access_iterator_tag
) {
211 typedef typename
E1::orientation_category orientation_category
;
212 return axpy_prod (e1
, e2
, v
, packed_random_access_iterator_tag (), orientation_category ());
216 /** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
219 \param e1 the matrix expression \c A
220 \param e2 the vector expression \c x
221 \param v the result vector \c v
222 \param init a boolean parameter
224 <tt>axpy_prod(A, x, v, init)</tt> implements the well known
225 axpy-product. Setting \a init to \c true is equivalent to call
226 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
227 defaults to \c true, but this may change in the future.
229 Up to now there are some specialisation for compressed
230 matrices that give a large speed up compared to prod.
237 \param V type of the result vector \c v
238 \param E1 type of a matrix expression \c A
239 \param E2 type of a vector expression \c x
241 template<class V
, class E1
, class E2
>
244 axpy_prod (const matrix_expression
<E1
> &e1
,
245 const vector_expression
<E2
> &e2
,
246 V
&v
, bool init
= true) {
247 typedef typename
V::value_type value_type
;
248 typedef typename
E2::const_iterator::iterator_category iterator_category
;
251 v
.assign (zero_vector
<value_type
> (e1 ().size1 ()));
252 #if BOOST_UBLAS_TYPE_CHECK
253 vector
<value_type
> cv (v
);
254 typedef typename type_traits
<value_type
>::real_type real_type
;
255 real_type
verrorbound (norm_1 (v
) + norm_1 (e1
) * norm_1 (e2
));
256 indexing_vector_assign
<scalar_plus_assign
> (cv
, prod (e1
, e2
));
258 axpy_prod (e1
, e2
, v
, iterator_category ());
259 #if BOOST_UBLAS_TYPE_CHECK
260 BOOST_UBLAS_CHECK (norm_1 (v
- cv
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * verrorbound
, internal_logic ());
264 template<class V
, class E1
, class E2
>
267 axpy_prod (const matrix_expression
<E1
> &e1
,
268 const vector_expression
<E2
> &e2
) {
269 typedef V vector_type
;
271 vector_type
v (e1 ().size1 ());
272 return axpy_prod (e1
, e2
, v
, true);
275 template<class V
, class E1
, class T2
, class IA2
, class TA2
>
278 axpy_prod (const vector_expression
<E1
> &e1
,
279 const compressed_matrix
<T2
, column_major
, 0, IA2
, TA2
> &e2
,
280 V
&v
, column_major_tag
) {
281 typedef typename
V::size_type size_type
;
282 typedef typename
V::value_type value_type
;
284 for (size_type j
= 0; j
< e2
.filled1 () -1; ++ j
) {
285 size_type begin
= e2
.index1_data () [j
];
286 size_type end
= e2
.index1_data () [j
+ 1];
287 value_type
t (v (j
));
288 for (size_type i
= begin
; i
< end
; ++ i
)
289 t
+= e2
.value_data () [i
] * e1 () (e2
.index2_data () [i
]);
295 template<class V
, class E1
, class T2
, class IA2
, class TA2
>
298 axpy_prod (const vector_expression
<E1
> &e1
,
299 const compressed_matrix
<T2
, row_major
, 0, IA2
, TA2
> &e2
,
300 V
&v
, row_major_tag
) {
301 typedef typename
V::size_type size_type
;
303 for (size_type i
= 0; i
< e2
.filled1 () -1; ++ i
) {
304 size_type begin
= e2
.index1_data () [i
];
305 size_type end
= e2
.index1_data () [i
+ 1];
306 for (size_type j
= begin
; j
< end
; ++ j
)
307 v (e2
.index2_data () [j
]) += e2
.value_data () [j
] * e1 () (i
);
313 template<class V
, class E1
, class T2
, class L2
, class IA2
, class TA2
>
316 axpy_prod (const vector_expression
<E1
> &e1
,
317 const compressed_matrix
<T2
, L2
, 0, IA2
, TA2
> &e2
,
318 V
&v
, bool init
= true) {
319 typedef typename
V::value_type value_type
;
320 typedef typename
L2::orientation_category orientation_category
;
323 v
.assign (zero_vector
<value_type
> (e2
.size2 ()));
324 #if BOOST_UBLAS_TYPE_CHECK
325 vector
<value_type
> cv (v
);
326 typedef typename type_traits
<value_type
>::real_type real_type
;
327 real_type
verrorbound (norm_1 (v
) + norm_1 (e1
) * norm_1 (e2
));
328 indexing_vector_assign
<scalar_plus_assign
> (cv
, prod (e1
, e2
));
330 axpy_prod (e1
, e2
, v
, orientation_category ());
331 #if BOOST_UBLAS_TYPE_CHECK
332 BOOST_UBLAS_CHECK (norm_1 (v
- cv
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * verrorbound
, internal_logic ());
336 template<class V
, class E1
, class T2
, class L2
, class IA2
, class TA2
>
339 axpy_prod (const vector_expression
<E1
> &e1
,
340 const compressed_matrix
<T2
, L2
, 0, IA2
, TA2
> &e2
) {
341 typedef V vector_type
;
343 vector_type
v (e2
.size2 ());
344 return axpy_prod (e1
, e2
, v
, true);
347 template<class V
, class E1
, class E2
>
350 axpy_prod (const vector_expression
<E1
> &e1
,
351 const matrix_expression
<E2
> &e2
,
352 V
&v
, packed_random_access_iterator_tag
, column_major_tag
) {
353 typedef const E1 expression1_type
;
354 typedef const E2 expression2_type
;
355 typedef typename
V::size_type size_type
;
357 typename
expression2_type::const_iterator2
it2 (e2 ().begin2 ());
358 typename
expression2_type::const_iterator2
it2_end (e2 ().end2 ());
359 while (it2
!= it2_end
) {
360 size_type
index2 (it2
.index2 ());
361 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
362 typename
expression2_type::const_iterator1
it1 (it2
.begin ());
363 typename
expression2_type::const_iterator1
it1_end (it2
.end ());
365 typename
expression2_type::const_iterator1
it1 (boost::numeric::ublas::begin (it2
, iterator2_tag ()));
366 typename
expression2_type::const_iterator1
it1_end (boost::numeric::ublas::end (it2
, iterator2_tag ()));
368 while (it1
!= it1_end
) {
369 v (index2
) += *it1
* e1 () (it1
.index1 ());
377 template<class V
, class E1
, class E2
>
380 axpy_prod (const vector_expression
<E1
> &e1
,
381 const matrix_expression
<E2
> &e2
,
382 V
&v
, packed_random_access_iterator_tag
, row_major_tag
) {
383 typedef const E1 expression1_type
;
384 typedef const E2 expression2_type
;
385 typedef typename
V::size_type size_type
;
387 typename
expression2_type::const_iterator1
it1 (e2 ().begin1 ());
388 typename
expression2_type::const_iterator1
it1_end (e2 ().end1 ());
389 while (it1
!= it1_end
) {
390 size_type
index1 (it1
.index1 ());
391 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
392 typename
expression2_type::const_iterator2
it2 (it1
.begin ());
393 typename
expression2_type::const_iterator2
it2_end (it1
.end ());
395 typename
expression2_type::const_iterator2
it2 (boost::numeric::ublas::begin (it1
, iterator1_tag ()));
396 typename
expression2_type::const_iterator2
it2_end (boost::numeric::ublas::end (it1
, iterator1_tag ()));
398 while (it2
!= it2_end
) {
399 v (it2
.index2 ()) += *it2
* e1 () (index1
);
407 template<class V
, class E1
, class E2
>
410 axpy_prod (const vector_expression
<E1
> &e1
,
411 const matrix_expression
<E2
> &e2
,
412 V
&v
, sparse_bidirectional_iterator_tag
) {
413 typedef const E1 expression1_type
;
414 typedef const E2 expression2_type
;
415 typedef typename
V::size_type size_type
;
417 typename
expression1_type::const_iterator
it (e1 ().begin ());
418 typename
expression1_type::const_iterator
it_end (e1 ().end ());
419 while (it
!= it_end
) {
420 v
.plus_assign (*it
* row (e2 (), it
.index ()));
427 template<class V
, class E1
, class E2
>
430 axpy_prod (const vector_expression
<E1
> &e1
,
431 const matrix_expression
<E2
> &e2
,
432 V
&v
, packed_random_access_iterator_tag
) {
433 typedef typename
E2::orientation_category orientation_category
;
434 return axpy_prod (e1
, e2
, v
, packed_random_access_iterator_tag (), orientation_category ());
438 /** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
441 \param e1 the vector expression \c x
442 \param e2 the matrix expression \c A
443 \param v the result vector \c v
444 \param init a boolean parameter
446 <tt>axpy_prod(x, A, v, init)</tt> implements the well known
447 axpy-product. Setting \a init to \c true is equivalent to call
448 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
449 defaults to \c true, but this may change in the future.
451 Up to now there are some specialisation for compressed
452 matrices that give a large speed up compared to prod.
459 \param V type of the result vector \c v
460 \param E1 type of a vector expression \c x
461 \param E2 type of a matrix expression \c A
463 template<class V
, class E1
, class E2
>
466 axpy_prod (const vector_expression
<E1
> &e1
,
467 const matrix_expression
<E2
> &e2
,
468 V
&v
, bool init
= true) {
469 typedef typename
V::value_type value_type
;
470 typedef typename
E1::const_iterator::iterator_category iterator_category
;
473 v
.assign (zero_vector
<value_type
> (e2 ().size2 ()));
474 #if BOOST_UBLAS_TYPE_CHECK
475 vector
<value_type
> cv (v
);
476 typedef typename type_traits
<value_type
>::real_type real_type
;
477 real_type
verrorbound (norm_1 (v
) + norm_1 (e1
) * norm_1 (e2
));
478 indexing_vector_assign
<scalar_plus_assign
> (cv
, prod (e1
, e2
));
480 axpy_prod (e1
, e2
, v
, iterator_category ());
481 #if BOOST_UBLAS_TYPE_CHECK
482 BOOST_UBLAS_CHECK (norm_1 (v
- cv
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * verrorbound
, internal_logic ());
486 template<class V
, class E1
, class E2
>
489 axpy_prod (const vector_expression
<E1
> &e1
,
490 const matrix_expression
<E2
> &e2
) {
491 typedef V vector_type
;
493 vector_type
v (e2 ().size2 ());
494 return axpy_prod (e1
, e2
, v
, true);
497 template<class M
, class E1
, class E2
, class TRI
>
500 axpy_prod (const matrix_expression
<E1
> &e1
,
501 const matrix_expression
<E2
> &e2
,
503 dense_proxy_tag
, row_major_tag
) {
504 typedef M matrix_type
;
505 typedef const E1 expression1_type
;
506 typedef const E2 expression2_type
;
507 typedef typename
M::size_type size_type
;
508 typedef typename
M::value_type value_type
;
510 #if BOOST_UBLAS_TYPE_CHECK
511 matrix
<value_type
, row_major
> cm (m
);
512 typedef typename type_traits
<value_type
>::real_type real_type
;
513 real_type
merrorbound (norm_1 (m
) + norm_1 (e1
) * norm_1 (e2
));
514 indexing_matrix_assign
<scalar_plus_assign
> (cm
, prod (e1
, e2
), row_major_tag ());
516 size_type
size1 (e1 ().size1 ());
517 size_type
size2 (e1 ().size2 ());
518 for (size_type i
= 0; i
< size1
; ++ i
)
519 for (size_type j
= 0; j
< size2
; ++ j
)
520 row (m
, i
).plus_assign (e1 () (i
, j
) * row (e2 (), j
));
521 #if BOOST_UBLAS_TYPE_CHECK
522 BOOST_UBLAS_CHECK (norm_1 (m
- cm
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * merrorbound
, internal_logic ());
526 template<class M
, class E1
, class E2
, class TRI
>
529 axpy_prod (const matrix_expression
<E1
> &e1
,
530 const matrix_expression
<E2
> &e2
,
532 sparse_proxy_tag
, row_major_tag
) {
533 typedef M matrix_type
;
534 typedef TRI triangular_restriction
;
535 typedef const E1 expression1_type
;
536 typedef const E2 expression2_type
;
537 typedef typename
M::size_type size_type
;
538 typedef typename
M::value_type value_type
;
540 #if BOOST_UBLAS_TYPE_CHECK
541 matrix
<value_type
, row_major
> cm (m
);
542 typedef typename type_traits
<value_type
>::real_type real_type
;
543 real_type
merrorbound (norm_1 (m
) + norm_1 (e1
) * norm_1 (e2
));
544 indexing_matrix_assign
<scalar_plus_assign
> (cm
, prod (e1
, e2
), row_major_tag ());
546 typename
expression1_type::const_iterator1
it1 (e1 ().begin1 ());
547 typename
expression1_type::const_iterator1
it1_end (e1 ().end1 ());
548 while (it1
!= it1_end
) {
549 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
550 typename
expression1_type::const_iterator2
it2 (it1
.begin ());
551 typename
expression1_type::const_iterator2
it2_end (it1
.end ());
553 typename
expression1_type::const_iterator2
it2 (boost::numeric::ublas::begin (it1
, iterator1_tag ()));
554 typename
expression1_type::const_iterator2
it2_end (boost::numeric::ublas::end (it1
, iterator1_tag ()));
556 while (it2
!= it2_end
) {
557 // row (m, it1.index1 ()).plus_assign (*it2 * row (e2 (), it2.index2 ()));
558 matrix_row
<expression2_type
> mr (e2 (), it2
.index2 ());
559 typename matrix_row
<expression2_type
>::const_iterator
itr (mr
.begin ());
560 typename matrix_row
<expression2_type
>::const_iterator
itr_end (mr
.end ());
561 while (itr
!= itr_end
) {
562 if (triangular_restriction::other (it1
.index1 (), itr
.index ()))
563 m (it1
.index1 (), itr
.index ()) += *it2
* *itr
;
570 #if BOOST_UBLAS_TYPE_CHECK
571 BOOST_UBLAS_CHECK (norm_1 (m
- cm
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * merrorbound
, internal_logic ());
576 template<class M
, class E1
, class E2
, class TRI
>
579 axpy_prod (const matrix_expression
<E1
> &e1
,
580 const matrix_expression
<E2
> &e2
,
582 dense_proxy_tag
, column_major_tag
) {
583 typedef M matrix_type
;
584 typedef const E1 expression1_type
;
585 typedef const E2 expression2_type
;
586 typedef typename
M::size_type size_type
;
587 typedef typename
M::value_type value_type
;
589 #if BOOST_UBLAS_TYPE_CHECK
590 matrix
<value_type
, column_major
> cm (m
);
591 typedef typename type_traits
<value_type
>::real_type real_type
;
592 real_type
merrorbound (norm_1 (m
) + norm_1 (e1
) * norm_1 (e2
));
593 indexing_matrix_assign
<scalar_plus_assign
> (cm
, prod (e1
, e2
), column_major_tag ());
595 size_type
size1 (e2 ().size1 ());
596 size_type
size2 (e2 ().size2 ());
597 for (size_type j
= 0; j
< size2
; ++ j
)
598 for (size_type i
= 0; i
< size1
; ++ i
)
599 column (m
, j
).plus_assign (e2 () (i
, j
) * column (e1 (), i
));
600 #if BOOST_UBLAS_TYPE_CHECK
601 BOOST_UBLAS_CHECK (norm_1 (m
- cm
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * merrorbound
, internal_logic ());
605 template<class M
, class E1
, class E2
, class TRI
>
608 axpy_prod (const matrix_expression
<E1
> &e1
,
609 const matrix_expression
<E2
> &e2
,
611 sparse_proxy_tag
, column_major_tag
) {
612 typedef M matrix_type
;
613 typedef TRI triangular_restriction
;
614 typedef const E1 expression1_type
;
615 typedef const E2 expression2_type
;
616 typedef typename
M::size_type size_type
;
617 typedef typename
M::value_type value_type
;
619 #if BOOST_UBLAS_TYPE_CHECK
620 matrix
<value_type
, column_major
> cm (m
);
621 typedef typename type_traits
<value_type
>::real_type real_type
;
622 real_type
merrorbound (norm_1 (m
) + norm_1 (e1
) * norm_1 (e2
));
623 indexing_matrix_assign
<scalar_plus_assign
> (cm
, prod (e1
, e2
), column_major_tag ());
625 typename
expression2_type::const_iterator2
it2 (e2 ().begin2 ());
626 typename
expression2_type::const_iterator2
it2_end (e2 ().end2 ());
627 while (it2
!= it2_end
) {
628 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
629 typename
expression2_type::const_iterator1
it1 (it2
.begin ());
630 typename
expression2_type::const_iterator1
it1_end (it2
.end ());
632 typename
expression2_type::const_iterator1
it1 (boost::numeric::ublas::begin (it2
, iterator2_tag ()));
633 typename
expression2_type::const_iterator1
it1_end (boost::numeric::ublas::end (it2
, iterator2_tag ()));
635 while (it1
!= it1_end
) {
636 // column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
637 matrix_column
<expression1_type
> mc (e1 (), it1
.index1 ());
638 typename matrix_column
<expression1_type
>::const_iterator
itc (mc
.begin ());
639 typename matrix_column
<expression1_type
>::const_iterator
itc_end (mc
.end ());
640 while (itc
!= itc_end
) {
641 if(triangular_restriction::other (itc
.index (), it2
.index2 ()))
642 m (itc
.index (), it2
.index2 ()) += *it1
* *itc
;
649 #if BOOST_UBLAS_TYPE_CHECK
650 BOOST_UBLAS_CHECK (norm_1 (m
- cm
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * merrorbound
, internal_logic ());
656 template<class M
, class E1
, class E2
, class TRI
>
659 axpy_prod (const matrix_expression
<E1
> &e1
,
660 const matrix_expression
<E2
> &e2
,
661 M
&m
, TRI
, bool init
= true) {
662 typedef typename
M::value_type value_type
;
663 typedef typename
M::storage_category storage_category
;
664 typedef typename
M::orientation_category orientation_category
;
665 typedef TRI triangular_restriction
;
668 m
.assign (zero_matrix
<value_type
> (e1 ().size1 (), e2 ().size2 ()));
669 return axpy_prod (e1
, e2
, m
, triangular_restriction (), storage_category (), orientation_category ());
671 template<class M
, class E1
, class E2
, class TRI
>
674 axpy_prod (const matrix_expression
<E1
> &e1
,
675 const matrix_expression
<E2
> &e2
,
677 typedef M matrix_type
;
678 typedef TRI triangular_restriction
;
680 matrix_type
m (e1 ().size1 (), e2 ().size2 ());
681 return axpy_prod (e1
, e2
, m
, triangular_restriction (), true);
684 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
687 \param e1 the matrix expression \c A
688 \param e2 the matrix expression \c X
689 \param m the result matrix \c M
690 \param init a boolean parameter
692 <tt>axpy_prod(A, X, M, init)</tt> implements the well known
693 axpy-product. Setting \a init to \c true is equivalent to call
694 <tt>M.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
695 defaults to \c true, but this may change in the future.
697 Up to now there are no specialisations.
704 \param M type of the result matrix \c M
705 \param E1 type of a matrix expression \c A
706 \param E2 type of a matrix expression \c X
708 template<class M
, class E1
, class E2
>
711 axpy_prod (const matrix_expression
<E1
> &e1
,
712 const matrix_expression
<E2
> &e2
,
713 M
&m
, bool init
= true) {
714 typedef typename
M::value_type value_type
;
715 typedef typename
M::storage_category storage_category
;
716 typedef typename
M::orientation_category orientation_category
;
719 m
.assign (zero_matrix
<value_type
> (e1 ().size1 (), e2 ().size2 ()));
720 return axpy_prod (e1
, e2
, m
, full (), storage_category (), orientation_category ());
722 template<class M
, class E1
, class E2
>
725 axpy_prod (const matrix_expression
<E1
> &e1
,
726 const matrix_expression
<E2
> &e2
) {
727 typedef M matrix_type
;
729 matrix_type
m (e1 ().size1 (), e2 ().size2 ());
730 return axpy_prod (e1
, e2
, m
, full (), true);
734 template<class M
, class E1
, class E2
>
737 opb_prod (const matrix_expression
<E1
> &e1
,
738 const matrix_expression
<E2
> &e2
,
740 dense_proxy_tag
, row_major_tag
) {
741 typedef M matrix_type
;
742 typedef const E1 expression1_type
;
743 typedef const E2 expression2_type
;
744 typedef typename
M::size_type size_type
;
745 typedef typename
M::value_type value_type
;
747 #if BOOST_UBLAS_TYPE_CHECK
748 matrix
<value_type
, row_major
> cm (m
);
749 typedef typename type_traits
<value_type
>::real_type real_type
;
750 real_type
merrorbound (norm_1 (m
) + norm_1 (e1
) * norm_1 (e2
));
751 indexing_matrix_assign
<scalar_plus_assign
> (cm
, prod (e1
, e2
), row_major_tag ());
753 size_type
size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
754 for (size_type k
= 0; k
< size
; ++ k
) {
755 vector
<value_type
> ce1 (column (e1 (), k
));
756 vector
<value_type
> re2 (row (e2 (), k
));
757 m
.plus_assign (outer_prod (ce1
, re2
));
759 #if BOOST_UBLAS_TYPE_CHECK
760 BOOST_UBLAS_CHECK (norm_1 (m
- cm
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * merrorbound
, internal_logic ());
765 template<class M
, class E1
, class E2
>
768 opb_prod (const matrix_expression
<E1
> &e1
,
769 const matrix_expression
<E2
> &e2
,
771 dense_proxy_tag
, column_major_tag
) {
772 typedef M matrix_type
;
773 typedef const E1 expression1_type
;
774 typedef const E2 expression2_type
;
775 typedef typename
M::size_type size_type
;
776 typedef typename
M::value_type value_type
;
778 #if BOOST_UBLAS_TYPE_CHECK
779 matrix
<value_type
, column_major
> cm (m
);
780 typedef typename type_traits
<value_type
>::real_type real_type
;
781 real_type
merrorbound (norm_1 (m
) + norm_1 (e1
) * norm_1 (e2
));
782 indexing_matrix_assign
<scalar_plus_assign
> (cm
, prod (e1
, e2
), column_major_tag ());
784 size_type
size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
785 for (size_type k
= 0; k
< size
; ++ k
) {
786 vector
<value_type
> ce1 (column (e1 (), k
));
787 vector
<value_type
> re2 (row (e2 (), k
));
788 m
.plus_assign (outer_prod (ce1
, re2
));
790 #if BOOST_UBLAS_TYPE_CHECK
791 BOOST_UBLAS_CHECK (norm_1 (m
- cm
) <= 2 * std::numeric_limits
<real_type
>::epsilon () * merrorbound
, internal_logic ());
798 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
801 \param e1 the matrix expression \c A
802 \param e2 the matrix expression \c X
803 \param m the result matrix \c M
804 \param init a boolean parameter
806 <tt>opb_prod(A, X, M, init)</tt> implements the well known
807 axpy-product. Setting \a init to \c true is equivalent to call
808 <tt>M.clear()</tt> before <tt>opb_prod</tt>. Currently \a init
809 defaults to \c true, but this may change in the future.
811 This function may give a speedup if \c A has less columns than
812 rows, because the product is computed as a sum of outer
820 \param M type of the result matrix \c M
821 \param E1 type of a matrix expression \c A
822 \param E2 type of a matrix expression \c X
824 template<class M
, class E1
, class E2
>
827 opb_prod (const matrix_expression
<E1
> &e1
,
828 const matrix_expression
<E2
> &e2
,
829 M
&m
, bool init
= true) {
830 typedef typename
M::value_type value_type
;
831 typedef typename
M::storage_category storage_category
;
832 typedef typename
M::orientation_category orientation_category
;
835 m
.assign (zero_matrix
<value_type
> (e1 ().size1 (), e2 ().size2 ()));
836 return opb_prod (e1
, e2
, m
, storage_category (), orientation_category ());
838 template<class M
, class E1
, class E2
>
841 opb_prod (const matrix_expression
<E1
> &e1
,
842 const matrix_expression
<E2
> &e2
) {
843 typedef M matrix_type
;
845 matrix_type
m (e1 ().size1 (), e2 ().size2 ());
846 return opb_prod (e1
, e2
, m
, true);