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 
13 #ifndef _BOOST_UBLAS_OPERATION_
14 #define _BOOST_UBLAS_OPERATION_
15 
16 #include <boost/numeric/ublas/matrix_proxy.hpp>
17 
18 /** \file operation.hpp
19  *  \brief This file contains some specialized products.
20  */
21 
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.
25 
26 namespace boost { namespace numeric { namespace ublas {
27 
28     template<class V, class T1, class L1, class IA1, class TA1, class E2>
29     BOOST_UBLAS_INLINE
30     V &
axpy_prod(const compressed_matrix<T1,L1,0,IA1,TA1> & e1,const vector_expression<E2> & e2,V & v,row_major_tag)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;
36 
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];
40             value_type t (v (i));
41             for (size_type j = begin; j < end; ++ j)
42                 t += e1.value_data () [j] * e2 () (e1.index2_data () [j]);
43             v (i) = t;
44         }
45         return v;
46     }
47 
48     template<class V, class T1, class L1, class IA1, class TA1, class E2>
49     BOOST_UBLAS_INLINE
50     V &
axpy_prod(const compressed_matrix<T1,L1,0,IA1,TA1> & e1,const vector_expression<E2> & e2,V & v,column_major_tag)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;
55 
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);
61         }
62         return v;
63     }
64 
65     // Dispatcher
66     template<class V, class T1, class L1, class IA1, class TA1, class E2>
67     BOOST_UBLAS_INLINE
68     V &
axpy_prod(const compressed_matrix<T1,L1,0,IA1,TA1> & e1,const vector_expression<E2> & e2,V & v,bool init=true)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;
74 
75         if (init)
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));
82 #endif
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 ());
86 #endif
87         return v;
88     }
89     template<class V, class T1, class L1, class IA1, class TA1, class E2>
90     BOOST_UBLAS_INLINE
91     V
axpy_prod(const compressed_matrix<T1,L1,0,IA1,TA1> & e1,const vector_expression<E2> & e2)92     axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
93                const vector_expression<E2> &e2) {
94         typedef V vector_type;
95 
96         vector_type v (e1.size1 ());
97         return axpy_prod (e1, e2, v, true);
98     }
99 
100     template<class V, class T1, class L1, class IA1, class TA1, class E2>
101     BOOST_UBLAS_INLINE
102     V &
axpy_prod(const coordinate_matrix<T1,L1,0,IA1,TA1> & e1,const vector_expression<E2> & e2,V & v,bool init=true)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;
109 
110         size_type size1 = e1.size1();
111         size_type size2 = e1.size2();
112 
113         if (init) {
114             noalias(v) = zero_vector<value_type>(size1);
115         }
116 
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);
121         }
122         return v;
123     }
124 
125     template<class V, class E1, class E2>
126     BOOST_UBLAS_INLINE
127     V &
axpy_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,V & v,packed_random_access_iterator_tag,row_major_tag)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;
133 
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 ());
141 #else
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 ()));
144 #endif
145             while (it2 != it2_end) {
146                 v (index1) += *it2 * e2 () (it2.index2 ());
147                 ++ it2;
148             }
149             ++ it1;
150         }
151         return v;
152     }
153 
154     template<class V, class E1, class E2>
155     BOOST_UBLAS_INLINE
156     V &
axpy_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,V & v,packed_random_access_iterator_tag,column_major_tag)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;
162 
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 ());
170 #else
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 ()));
173 #endif
174             while (it1 != it1_end) {
175                 v (it1.index1 ()) += *it1 * e2 () (index2);
176                 ++ it1;
177             }
178             ++ it2;
179         }
180         return v;
181     }
182 
183     template<class V, class E1, class E2>
184     BOOST_UBLAS_INLINE
185     V &
axpy_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,V & v,sparse_bidirectional_iterator_tag)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;
190 
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);
195             ++ it;
196         }
197         return v;
198     }
199 
200     // Dispatcher
201     template<class V, class E1, class E2>
202     BOOST_UBLAS_INLINE
203     V &
axpy_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,V & v,packed_random_access_iterator_tag)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 ());
209     }
210 
211 
212   /** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
213           optimized fashion.
214 
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
219 
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.
224 
225           Up to now there are some specialisation for compressed
226           matrices that give a large speed up compared to prod.
227 
228           \ingroup blas2
229 
230           \internal
231 
232           template parameters:
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
236   */
237     template<class V, class E1, class E2>
238     BOOST_UBLAS_INLINE
239     V &
axpy_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,V & v,bool init=true)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;
245 
246         if (init)
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));
253 #endif
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 ());
257 #endif
258         return v;
259     }
260     template<class V, class E1, class E2>
261     BOOST_UBLAS_INLINE
262     V
axpy_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2)263     axpy_prod (const matrix_expression<E1> &e1,
264                const vector_expression<E2> &e2) {
265         typedef V vector_type;
266 
267         vector_type v (e1 ().size1 ());
268         return axpy_prod (e1, e2, v, true);
269     }
270 
271     template<class V, class E1, class T2, class IA2, class TA2>
272     BOOST_UBLAS_INLINE
273     V &
axpy_prod(const vector_expression<E1> & e1,const compressed_matrix<T2,column_major,0,IA2,TA2> & e2,V & v,column_major_tag)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;
279 
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]);
286             v (j) = t;
287         }
288         return v;
289     }
290 
291     template<class V, class E1, class T2, class IA2, class TA2>
292     BOOST_UBLAS_INLINE
293     V &
axpy_prod(const vector_expression<E1> & e1,const compressed_matrix<T2,row_major,0,IA2,TA2> & e2,V & v,row_major_tag)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;
298 
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);
304         }
305         return v;
306     }
307 
308     // Dispatcher
309     template<class V, class E1, class T2, class L2, class IA2, class TA2>
310     BOOST_UBLAS_INLINE
311     V &
axpy_prod(const vector_expression<E1> & e1,const compressed_matrix<T2,L2,0,IA2,TA2> & e2,V & v,bool init=true)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;
317 
318         if (init)
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));
325 #endif
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 ());
329 #endif
330         return v;
331     }
332     template<class V, class E1, class T2, class L2, class IA2, class TA2>
333     BOOST_UBLAS_INLINE
334     V
axpy_prod(const vector_expression<E1> & e1,const compressed_matrix<T2,L2,0,IA2,TA2> & e2)335     axpy_prod (const vector_expression<E1> &e1,
336                const compressed_matrix<T2, L2, 0, IA2, TA2> &e2) {
337         typedef V vector_type;
338 
339         vector_type v (e2.size2 ());
340         return axpy_prod (e1, e2, v, true);
341     }
342 
343     template<class V, class E1, class E2>
344     BOOST_UBLAS_INLINE
345     V &
axpy_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,V & v,packed_random_access_iterator_tag,column_major_tag)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;
351 
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 ());
359 #else
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 ()));
362 #endif
363             while (it1 != it1_end) {
364                 v (index2) += *it1 * e1 () (it1.index1 ());
365                 ++ it1;
366             }
367             ++ it2;
368         }
369         return v;
370     }
371 
372     template<class V, class E1, class E2>
373     BOOST_UBLAS_INLINE
374     V &
axpy_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,V & v,packed_random_access_iterator_tag,row_major_tag)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;
380 
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 ());
388 #else
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 ()));
391 #endif
392             while (it2 != it2_end) {
393                 v (it2.index2 ()) += *it2 * e1 () (index1);
394                 ++ it2;
395             }
396             ++ it1;
397         }
398         return v;
399     }
400 
401     template<class V, class E1, class E2>
402     BOOST_UBLAS_INLINE
403     V &
axpy_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,V & v,sparse_bidirectional_iterator_tag)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;
408 
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 ()));
413             ++ it;
414         }
415         return v;
416     }
417 
418     // Dispatcher
419     template<class V, class E1, class E2>
420     BOOST_UBLAS_INLINE
421     V &
axpy_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,V & v,packed_random_access_iterator_tag)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 ());
427     }
428 
429 
430   /** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
431           optimized fashion.
432 
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
437 
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.
442 
443           Up to now there are some specialisation for compressed
444           matrices that give a large speed up compared to prod.
445 
446           \ingroup blas2
447 
448           \internal
449 
450           template parameters:
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
454   */
455     template<class V, class E1, class E2>
456     BOOST_UBLAS_INLINE
457     V &
axpy_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,V & v,bool init=true)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;
463 
464         if (init)
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));
471 #endif
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 ());
475 #endif
476         return v;
477     }
478     template<class V, class E1, class E2>
479     BOOST_UBLAS_INLINE
480     V
axpy_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2)481     axpy_prod (const vector_expression<E1> &e1,
482                const matrix_expression<E2> &e2) {
483         typedef V vector_type;
484 
485         vector_type v (e2 ().size2 ());
486         return axpy_prod (e1, e2, v, true);
487     }
488 
489     template<class M, class E1, class E2, class TRI>
490     BOOST_UBLAS_INLINE
491     M &
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,TRI,dense_proxy_tag,row_major_tag)492     axpy_prod (const matrix_expression<E1> &e1,
493                const matrix_expression<E2> &e2,
494                M &m, TRI,
495                dense_proxy_tag, row_major_tag) {
496 
497         typedef typename M::size_type size_type;
498 
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 ());
505 #endif
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 ());
513 #endif
514         return m;
515     }
516     template<class M, class E1, class E2, class TRI>
517     BOOST_UBLAS_INLINE
518     M &
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,TRI,sparse_proxy_tag,row_major_tag)519     axpy_prod (const matrix_expression<E1> &e1,
520                const matrix_expression<E2> &e2,
521                M &m, TRI,
522                sparse_proxy_tag, row_major_tag) {
523 
524         typedef TRI triangular_restriction;
525         typedef const E1 expression1_type;
526         typedef const E2 expression2_type;
527 
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 ());
534 #endif
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 ());
541 #else
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 ()));
544 #endif
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;
553                     ++ itr;
554                 }
555                 ++ it2;
556             }
557             ++ it1;
558         }
559 #if BOOST_UBLAS_TYPE_CHECK
560         BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
561 #endif
562         return m;
563     }
564 
565     template<class M, class E1, class E2, class TRI>
566     BOOST_UBLAS_INLINE
567     M &
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,TRI,dense_proxy_tag,column_major_tag)568     axpy_prod (const matrix_expression<E1> &e1,
569                const matrix_expression<E2> &e2,
570                M &m, TRI,
571                dense_proxy_tag, column_major_tag) {
572         typedef typename M::size_type size_type;
573 
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 ());
580 #endif
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 ());
588 #endif
589         return m;
590     }
591     template<class M, class E1, class E2, class TRI>
592     BOOST_UBLAS_INLINE
593     M &
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,TRI,sparse_proxy_tag,column_major_tag)594     axpy_prod (const matrix_expression<E1> &e1,
595                const matrix_expression<E2> &e2,
596                M &m, TRI,
597                sparse_proxy_tag, column_major_tag) {
598         typedef TRI triangular_restriction;
599         typedef const E1 expression1_type;
600         typedef const E2 expression2_type;
601 
602 
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 ());
609 #endif
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 ());
616 #else
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 ()));
619 #endif
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;
628                     ++ itc;
629                 }
630                 ++ it1;
631             }
632             ++ it2;
633         }
634 #if BOOST_UBLAS_TYPE_CHECK
635         BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
636 #endif
637         return m;
638     }
639 
640     // Dispatcher
641     template<class M, class E1, class E2, class TRI>
642     BOOST_UBLAS_INLINE
643     M &
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,TRI,bool init=true)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;
651 
652         if (init)
653             m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
654         return axpy_prod (e1, e2, m, triangular_restriction (), storage_category (), orientation_category ());
655     }
656     template<class M, class E1, class E2, class TRI>
657     BOOST_UBLAS_INLINE
658     M
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,TRI)659     axpy_prod (const matrix_expression<E1> &e1,
660                const matrix_expression<E2> &e2,
661                TRI) {
662         typedef M matrix_type;
663         typedef TRI triangular_restriction;
664 
665         matrix_type m (e1 ().size1 (), e2 ().size2 ());
666         return axpy_prod (e1, e2, m, triangular_restriction (), true);
667     }
668 
669   /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
670           optimized fashion.
671 
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
676 
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.
681 
682           Up to now there are no specialisations.
683 
684           \ingroup blas3
685 
686           \internal
687 
688           template parameters:
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
692   */
693     template<class M, class E1, class E2>
694     BOOST_UBLAS_INLINE
695     M &
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,bool init=true)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;
702 
703         if (init)
704             m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
705         return axpy_prod (e1, e2, m, full (), storage_category (), orientation_category ());
706     }
707     template<class M, class E1, class E2>
708     BOOST_UBLAS_INLINE
709     M
axpy_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)710     axpy_prod (const matrix_expression<E1> &e1,
711                const matrix_expression<E2> &e2) {
712         typedef M matrix_type;
713 
714         matrix_type m (e1 ().size1 (), e2 ().size2 ());
715         return axpy_prod (e1, e2, m, full (), true);
716     }
717 
718 
719     template<class M, class E1, class E2>
720     BOOST_UBLAS_INLINE
721     M &
opb_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,dense_proxy_tag,row_major_tag)722     opb_prod (const matrix_expression<E1> &e1,
723               const matrix_expression<E2> &e2,
724               M &m,
725               dense_proxy_tag, row_major_tag) {
726         typedef typename M::size_type size_type;
727         typedef typename M::value_type value_type;
728 
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 ());
734 #endif
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));
740         }
741 #if BOOST_UBLAS_TYPE_CHECK
742         BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
743 #endif
744         return m;
745     }
746 
747     template<class M, class E1, class E2>
748     BOOST_UBLAS_INLINE
749     M &
opb_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,dense_proxy_tag,column_major_tag)750     opb_prod (const matrix_expression<E1> &e1,
751               const matrix_expression<E2> &e2,
752               M &m,
753               dense_proxy_tag, column_major_tag) {
754         typedef typename M::size_type size_type;
755         typedef typename M::value_type value_type;
756 
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 ());
762 #endif
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));
768         }
769 #if BOOST_UBLAS_TYPE_CHECK
770         BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
771 #endif
772         return m;
773     }
774 
775     // Dispatcher
776 
777   /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
778           optimized fashion.
779 
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
784 
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.
789 
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
792           products.
793 
794           \ingroup blas3
795 
796           \internal
797 
798           template parameters:
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
802   */
803     template<class M, class E1, class E2>
804     BOOST_UBLAS_INLINE
805     M &
opb_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m,bool init=true)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;
812 
813         if (init)
814             m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
815         return opb_prod (e1, e2, m, storage_category (), orientation_category ());
816     }
817     template<class M, class E1, class E2>
818     BOOST_UBLAS_INLINE
819     M
opb_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)820     opb_prod (const matrix_expression<E1> &e1,
821               const matrix_expression<E2> &e2) {
822         typedef M matrix_type;
823 
824         matrix_type m (e1 ().size1 (), e2 ().size2 ());
825         return opb_prod (e1, e2, m, true);
826     }
827 
828 }}}
829 
830 #endif
831