Chris@16
|
1 //
|
Chris@16
|
2 // Copyright (c) 2000-2002
|
Chris@16
|
3 // Joerg Walter, Mathias Koch
|
Chris@16
|
4 //
|
Chris@16
|
5 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
6 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 //
|
Chris@16
|
9 // The authors gratefully acknowledge the support of
|
Chris@16
|
10 // GeNeSys mbH & Co. KG in producing this work.
|
Chris@16
|
11 //
|
Chris@16
|
12
|
Chris@16
|
13 #ifndef _BOOST_UBLAS_OPERATION_
|
Chris@16
|
14 #define _BOOST_UBLAS_OPERATION_
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/numeric/ublas/matrix_proxy.hpp>
|
Chris@16
|
17
|
Chris@16
|
18 /** \file operation.hpp
|
Chris@16
|
19 * \brief This file contains some specialized products.
|
Chris@16
|
20 */
|
Chris@16
|
21
|
Chris@16
|
22 // axpy-based products
|
Chris@16
|
23 // Alexei Novakov had a lot of ideas to improve these. Thanks.
|
Chris@16
|
24 // Hendrik Kueck proposed some new kernel. Thanks again.
|
Chris@16
|
25
|
Chris@16
|
26 namespace boost { namespace numeric { namespace ublas {
|
Chris@16
|
27
|
Chris@16
|
28 template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
Chris@16
|
29 BOOST_UBLAS_INLINE
|
Chris@16
|
30 V &
|
Chris@16
|
31 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
Chris@16
|
32 const vector_expression<E2> &e2,
|
Chris@16
|
33 V &v, row_major_tag) {
|
Chris@16
|
34 typedef typename V::size_type size_type;
|
Chris@16
|
35 typedef typename V::value_type value_type;
|
Chris@16
|
36
|
Chris@16
|
37 for (size_type i = 0; i < e1.filled1 () -1; ++ i) {
|
Chris@16
|
38 size_type begin = e1.index1_data () [i];
|
Chris@16
|
39 size_type end = e1.index1_data () [i + 1];
|
Chris@16
|
40 value_type t (v (i));
|
Chris@16
|
41 for (size_type j = begin; j < end; ++ j)
|
Chris@16
|
42 t += e1.value_data () [j] * e2 () (e1.index2_data () [j]);
|
Chris@16
|
43 v (i) = t;
|
Chris@16
|
44 }
|
Chris@16
|
45 return v;
|
Chris@16
|
46 }
|
Chris@16
|
47
|
Chris@16
|
48 template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
Chris@16
|
49 BOOST_UBLAS_INLINE
|
Chris@16
|
50 V &
|
Chris@16
|
51 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
Chris@16
|
52 const vector_expression<E2> &e2,
|
Chris@16
|
53 V &v, column_major_tag) {
|
Chris@16
|
54 typedef typename V::size_type size_type;
|
Chris@16
|
55
|
Chris@16
|
56 for (size_type j = 0; j < e1.filled1 () -1; ++ j) {
|
Chris@16
|
57 size_type begin = e1.index1_data () [j];
|
Chris@16
|
58 size_type end = e1.index1_data () [j + 1];
|
Chris@16
|
59 for (size_type i = begin; i < end; ++ i)
|
Chris@16
|
60 v (e1.index2_data () [i]) += e1.value_data () [i] * e2 () (j);
|
Chris@16
|
61 }
|
Chris@16
|
62 return v;
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 // Dispatcher
|
Chris@16
|
66 template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
Chris@16
|
67 BOOST_UBLAS_INLINE
|
Chris@16
|
68 V &
|
Chris@16
|
69 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
Chris@16
|
70 const vector_expression<E2> &e2,
|
Chris@16
|
71 V &v, bool init = true) {
|
Chris@16
|
72 typedef typename V::value_type value_type;
|
Chris@16
|
73 typedef typename L1::orientation_category orientation_category;
|
Chris@16
|
74
|
Chris@16
|
75 if (init)
|
Chris@16
|
76 v.assign (zero_vector<value_type> (e1.size1 ()));
|
Chris@16
|
77 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
78 vector<value_type> cv (v);
|
Chris@16
|
79 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
80 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
81 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
Chris@16
|
82 #endif
|
Chris@16
|
83 axpy_prod (e1, e2, v, orientation_category ());
|
Chris@16
|
84 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
85 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
Chris@16
|
86 #endif
|
Chris@16
|
87 return v;
|
Chris@16
|
88 }
|
Chris@16
|
89 template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
Chris@16
|
90 BOOST_UBLAS_INLINE
|
Chris@16
|
91 V
|
Chris@16
|
92 axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
Chris@16
|
93 const vector_expression<E2> &e2) {
|
Chris@16
|
94 typedef V vector_type;
|
Chris@16
|
95
|
Chris@16
|
96 vector_type v (e1.size1 ());
|
Chris@16
|
97 return axpy_prod (e1, e2, v, true);
|
Chris@16
|
98 }
|
Chris@16
|
99
|
Chris@16
|
100 template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
Chris@16
|
101 BOOST_UBLAS_INLINE
|
Chris@16
|
102 V &
|
Chris@16
|
103 axpy_prod (const coordinate_matrix<T1, L1, 0, IA1, TA1> &e1,
|
Chris@16
|
104 const vector_expression<E2> &e2,
|
Chris@16
|
105 V &v, bool init = true) {
|
Chris@16
|
106 typedef typename V::size_type size_type;
|
Chris@16
|
107 typedef typename V::value_type value_type;
|
Chris@16
|
108 typedef L1 layout_type;
|
Chris@16
|
109
|
Chris@16
|
110 size_type size1 = e1.size1();
|
Chris@16
|
111 size_type size2 = e1.size2();
|
Chris@16
|
112
|
Chris@16
|
113 if (init) {
|
Chris@16
|
114 noalias(v) = zero_vector<value_type>(size1);
|
Chris@16
|
115 }
|
Chris@16
|
116
|
Chris@16
|
117 for (size_type i = 0; i < e1.nnz(); ++i) {
|
Chris@16
|
118 size_type row_index = layout_type::index_M( e1.index1_data () [i], e1.index2_data () [i] );
|
Chris@16
|
119 size_type col_index = layout_type::index_m( e1.index1_data () [i], e1.index2_data () [i] );
|
Chris@16
|
120 v( row_index ) += e1.value_data () [i] * e2 () (col_index);
|
Chris@16
|
121 }
|
Chris@16
|
122 return v;
|
Chris@16
|
123 }
|
Chris@16
|
124
|
Chris@16
|
125 template<class V, class E1, class E2>
|
Chris@16
|
126 BOOST_UBLAS_INLINE
|
Chris@16
|
127 V &
|
Chris@16
|
128 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
129 const vector_expression<E2> &e2,
|
Chris@16
|
130 V &v, packed_random_access_iterator_tag, row_major_tag) {
|
Chris@16
|
131 typedef const E1 expression1_type;
|
Chris@16
|
132 typedef typename V::size_type size_type;
|
Chris@16
|
133
|
Chris@16
|
134 typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
|
Chris@16
|
135 typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
|
Chris@16
|
136 while (it1 != it1_end) {
|
Chris@16
|
137 size_type index1 (it1.index1 ());
|
Chris@16
|
138 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
Chris@16
|
139 typename expression1_type::const_iterator2 it2 (it1.begin ());
|
Chris@16
|
140 typename expression1_type::const_iterator2 it2_end (it1.end ());
|
Chris@16
|
141 #else
|
Chris@16
|
142 typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
|
Chris@16
|
143 typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
|
Chris@16
|
144 #endif
|
Chris@16
|
145 while (it2 != it2_end) {
|
Chris@16
|
146 v (index1) += *it2 * e2 () (it2.index2 ());
|
Chris@16
|
147 ++ it2;
|
Chris@16
|
148 }
|
Chris@16
|
149 ++ it1;
|
Chris@16
|
150 }
|
Chris@16
|
151 return v;
|
Chris@16
|
152 }
|
Chris@16
|
153
|
Chris@16
|
154 template<class V, class E1, class E2>
|
Chris@16
|
155 BOOST_UBLAS_INLINE
|
Chris@16
|
156 V &
|
Chris@16
|
157 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
158 const vector_expression<E2> &e2,
|
Chris@16
|
159 V &v, packed_random_access_iterator_tag, column_major_tag) {
|
Chris@16
|
160 typedef const E1 expression1_type;
|
Chris@16
|
161 typedef typename V::size_type size_type;
|
Chris@16
|
162
|
Chris@16
|
163 typename expression1_type::const_iterator2 it2 (e1 ().begin2 ());
|
Chris@16
|
164 typename expression1_type::const_iterator2 it2_end (e1 ().end2 ());
|
Chris@16
|
165 while (it2 != it2_end) {
|
Chris@16
|
166 size_type index2 (it2.index2 ());
|
Chris@16
|
167 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
Chris@16
|
168 typename expression1_type::const_iterator1 it1 (it2.begin ());
|
Chris@16
|
169 typename expression1_type::const_iterator1 it1_end (it2.end ());
|
Chris@16
|
170 #else
|
Chris@16
|
171 typename expression1_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
|
Chris@16
|
172 typename expression1_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
|
Chris@16
|
173 #endif
|
Chris@16
|
174 while (it1 != it1_end) {
|
Chris@16
|
175 v (it1.index1 ()) += *it1 * e2 () (index2);
|
Chris@16
|
176 ++ it1;
|
Chris@16
|
177 }
|
Chris@16
|
178 ++ it2;
|
Chris@16
|
179 }
|
Chris@16
|
180 return v;
|
Chris@16
|
181 }
|
Chris@16
|
182
|
Chris@16
|
183 template<class V, class E1, class E2>
|
Chris@16
|
184 BOOST_UBLAS_INLINE
|
Chris@16
|
185 V &
|
Chris@16
|
186 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
187 const vector_expression<E2> &e2,
|
Chris@16
|
188 V &v, sparse_bidirectional_iterator_tag) {
|
Chris@16
|
189 typedef const E2 expression2_type;
|
Chris@16
|
190
|
Chris@16
|
191 typename expression2_type::const_iterator it (e2 ().begin ());
|
Chris@16
|
192 typename expression2_type::const_iterator it_end (e2 ().end ());
|
Chris@16
|
193 while (it != it_end) {
|
Chris@16
|
194 v.plus_assign (column (e1 (), it.index ()) * *it);
|
Chris@16
|
195 ++ it;
|
Chris@16
|
196 }
|
Chris@16
|
197 return v;
|
Chris@16
|
198 }
|
Chris@16
|
199
|
Chris@16
|
200 // Dispatcher
|
Chris@16
|
201 template<class V, class E1, class E2>
|
Chris@16
|
202 BOOST_UBLAS_INLINE
|
Chris@16
|
203 V &
|
Chris@16
|
204 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
205 const vector_expression<E2> &e2,
|
Chris@16
|
206 V &v, packed_random_access_iterator_tag) {
|
Chris@16
|
207 typedef typename E1::orientation_category orientation_category;
|
Chris@16
|
208 return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@16
|
211
|
Chris@16
|
212 /** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
|
Chris@16
|
213 optimized fashion.
|
Chris@16
|
214
|
Chris@16
|
215 \param e1 the matrix expression \c A
|
Chris@16
|
216 \param e2 the vector expression \c x
|
Chris@16
|
217 \param v the result vector \c v
|
Chris@16
|
218 \param init a boolean parameter
|
Chris@16
|
219
|
Chris@16
|
220 <tt>axpy_prod(A, x, v, init)</tt> implements the well known
|
Chris@16
|
221 axpy-product. Setting \a init to \c true is equivalent to call
|
Chris@16
|
222 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
|
Chris@16
|
223 defaults to \c true, but this may change in the future.
|
Chris@16
|
224
|
Chris@16
|
225 Up to now there are some specialisation for compressed
|
Chris@16
|
226 matrices that give a large speed up compared to prod.
|
Chris@16
|
227
|
Chris@16
|
228 \ingroup blas2
|
Chris@16
|
229
|
Chris@16
|
230 \internal
|
Chris@16
|
231
|
Chris@16
|
232 template parameters:
|
Chris@16
|
233 \param V type of the result vector \c v
|
Chris@16
|
234 \param E1 type of a matrix expression \c A
|
Chris@16
|
235 \param E2 type of a vector expression \c x
|
Chris@16
|
236 */
|
Chris@16
|
237 template<class V, class E1, class E2>
|
Chris@16
|
238 BOOST_UBLAS_INLINE
|
Chris@16
|
239 V &
|
Chris@16
|
240 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
241 const vector_expression<E2> &e2,
|
Chris@16
|
242 V &v, bool init = true) {
|
Chris@16
|
243 typedef typename V::value_type value_type;
|
Chris@16
|
244 typedef typename E2::const_iterator::iterator_category iterator_category;
|
Chris@16
|
245
|
Chris@16
|
246 if (init)
|
Chris@16
|
247 v.assign (zero_vector<value_type> (e1 ().size1 ()));
|
Chris@16
|
248 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
249 vector<value_type> cv (v);
|
Chris@16
|
250 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
251 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
252 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
Chris@16
|
253 #endif
|
Chris@16
|
254 axpy_prod (e1, e2, v, iterator_category ());
|
Chris@16
|
255 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
256 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
Chris@16
|
257 #endif
|
Chris@16
|
258 return v;
|
Chris@16
|
259 }
|
Chris@16
|
260 template<class V, class E1, class E2>
|
Chris@16
|
261 BOOST_UBLAS_INLINE
|
Chris@16
|
262 V
|
Chris@16
|
263 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
264 const vector_expression<E2> &e2) {
|
Chris@16
|
265 typedef V vector_type;
|
Chris@16
|
266
|
Chris@16
|
267 vector_type v (e1 ().size1 ());
|
Chris@16
|
268 return axpy_prod (e1, e2, v, true);
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 template<class V, class E1, class T2, class IA2, class TA2>
|
Chris@16
|
272 BOOST_UBLAS_INLINE
|
Chris@16
|
273 V &
|
Chris@16
|
274 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
275 const compressed_matrix<T2, column_major, 0, IA2, TA2> &e2,
|
Chris@16
|
276 V &v, column_major_tag) {
|
Chris@16
|
277 typedef typename V::size_type size_type;
|
Chris@16
|
278 typedef typename V::value_type value_type;
|
Chris@16
|
279
|
Chris@16
|
280 for (size_type j = 0; j < e2.filled1 () -1; ++ j) {
|
Chris@16
|
281 size_type begin = e2.index1_data () [j];
|
Chris@16
|
282 size_type end = e2.index1_data () [j + 1];
|
Chris@16
|
283 value_type t (v (j));
|
Chris@16
|
284 for (size_type i = begin; i < end; ++ i)
|
Chris@16
|
285 t += e2.value_data () [i] * e1 () (e2.index2_data () [i]);
|
Chris@16
|
286 v (j) = t;
|
Chris@16
|
287 }
|
Chris@16
|
288 return v;
|
Chris@16
|
289 }
|
Chris@16
|
290
|
Chris@16
|
291 template<class V, class E1, class T2, class IA2, class TA2>
|
Chris@16
|
292 BOOST_UBLAS_INLINE
|
Chris@16
|
293 V &
|
Chris@16
|
294 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
295 const compressed_matrix<T2, row_major, 0, IA2, TA2> &e2,
|
Chris@16
|
296 V &v, row_major_tag) {
|
Chris@16
|
297 typedef typename V::size_type size_type;
|
Chris@16
|
298
|
Chris@16
|
299 for (size_type i = 0; i < e2.filled1 () -1; ++ i) {
|
Chris@16
|
300 size_type begin = e2.index1_data () [i];
|
Chris@16
|
301 size_type end = e2.index1_data () [i + 1];
|
Chris@16
|
302 for (size_type j = begin; j < end; ++ j)
|
Chris@16
|
303 v (e2.index2_data () [j]) += e2.value_data () [j] * e1 () (i);
|
Chris@16
|
304 }
|
Chris@16
|
305 return v;
|
Chris@16
|
306 }
|
Chris@16
|
307
|
Chris@16
|
308 // Dispatcher
|
Chris@16
|
309 template<class V, class E1, class T2, class L2, class IA2, class TA2>
|
Chris@16
|
310 BOOST_UBLAS_INLINE
|
Chris@16
|
311 V &
|
Chris@16
|
312 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
313 const compressed_matrix<T2, L2, 0, IA2, TA2> &e2,
|
Chris@16
|
314 V &v, bool init = true) {
|
Chris@16
|
315 typedef typename V::value_type value_type;
|
Chris@16
|
316 typedef typename L2::orientation_category orientation_category;
|
Chris@16
|
317
|
Chris@16
|
318 if (init)
|
Chris@16
|
319 v.assign (zero_vector<value_type> (e2.size2 ()));
|
Chris@16
|
320 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
321 vector<value_type> cv (v);
|
Chris@16
|
322 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
323 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
324 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
Chris@16
|
325 #endif
|
Chris@16
|
326 axpy_prod (e1, e2, v, orientation_category ());
|
Chris@16
|
327 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
328 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
Chris@16
|
329 #endif
|
Chris@16
|
330 return v;
|
Chris@16
|
331 }
|
Chris@16
|
332 template<class V, class E1, class T2, class L2, class IA2, class TA2>
|
Chris@16
|
333 BOOST_UBLAS_INLINE
|
Chris@16
|
334 V
|
Chris@16
|
335 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
336 const compressed_matrix<T2, L2, 0, IA2, TA2> &e2) {
|
Chris@16
|
337 typedef V vector_type;
|
Chris@16
|
338
|
Chris@16
|
339 vector_type v (e2.size2 ());
|
Chris@16
|
340 return axpy_prod (e1, e2, v, true);
|
Chris@16
|
341 }
|
Chris@16
|
342
|
Chris@16
|
343 template<class V, class E1, class E2>
|
Chris@16
|
344 BOOST_UBLAS_INLINE
|
Chris@16
|
345 V &
|
Chris@16
|
346 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
347 const matrix_expression<E2> &e2,
|
Chris@16
|
348 V &v, packed_random_access_iterator_tag, column_major_tag) {
|
Chris@16
|
349 typedef const E2 expression2_type;
|
Chris@16
|
350 typedef typename V::size_type size_type;
|
Chris@16
|
351
|
Chris@16
|
352 typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
|
Chris@16
|
353 typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
|
Chris@16
|
354 while (it2 != it2_end) {
|
Chris@16
|
355 size_type index2 (it2.index2 ());
|
Chris@16
|
356 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
Chris@16
|
357 typename expression2_type::const_iterator1 it1 (it2.begin ());
|
Chris@16
|
358 typename expression2_type::const_iterator1 it1_end (it2.end ());
|
Chris@16
|
359 #else
|
Chris@16
|
360 typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
|
Chris@16
|
361 typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
|
Chris@16
|
362 #endif
|
Chris@16
|
363 while (it1 != it1_end) {
|
Chris@16
|
364 v (index2) += *it1 * e1 () (it1.index1 ());
|
Chris@16
|
365 ++ it1;
|
Chris@16
|
366 }
|
Chris@16
|
367 ++ it2;
|
Chris@16
|
368 }
|
Chris@16
|
369 return v;
|
Chris@16
|
370 }
|
Chris@16
|
371
|
Chris@16
|
372 template<class V, class E1, class E2>
|
Chris@16
|
373 BOOST_UBLAS_INLINE
|
Chris@16
|
374 V &
|
Chris@16
|
375 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
376 const matrix_expression<E2> &e2,
|
Chris@16
|
377 V &v, packed_random_access_iterator_tag, row_major_tag) {
|
Chris@16
|
378 typedef const E2 expression2_type;
|
Chris@16
|
379 typedef typename V::size_type size_type;
|
Chris@16
|
380
|
Chris@16
|
381 typename expression2_type::const_iterator1 it1 (e2 ().begin1 ());
|
Chris@16
|
382 typename expression2_type::const_iterator1 it1_end (e2 ().end1 ());
|
Chris@16
|
383 while (it1 != it1_end) {
|
Chris@16
|
384 size_type index1 (it1.index1 ());
|
Chris@16
|
385 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
Chris@16
|
386 typename expression2_type::const_iterator2 it2 (it1.begin ());
|
Chris@16
|
387 typename expression2_type::const_iterator2 it2_end (it1.end ());
|
Chris@16
|
388 #else
|
Chris@16
|
389 typename expression2_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
|
Chris@16
|
390 typename expression2_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
|
Chris@16
|
391 #endif
|
Chris@16
|
392 while (it2 != it2_end) {
|
Chris@16
|
393 v (it2.index2 ()) += *it2 * e1 () (index1);
|
Chris@16
|
394 ++ it2;
|
Chris@16
|
395 }
|
Chris@16
|
396 ++ it1;
|
Chris@16
|
397 }
|
Chris@16
|
398 return v;
|
Chris@16
|
399 }
|
Chris@16
|
400
|
Chris@16
|
401 template<class V, class E1, class E2>
|
Chris@16
|
402 BOOST_UBLAS_INLINE
|
Chris@16
|
403 V &
|
Chris@16
|
404 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
405 const matrix_expression<E2> &e2,
|
Chris@16
|
406 V &v, sparse_bidirectional_iterator_tag) {
|
Chris@16
|
407 typedef const E1 expression1_type;
|
Chris@16
|
408
|
Chris@16
|
409 typename expression1_type::const_iterator it (e1 ().begin ());
|
Chris@16
|
410 typename expression1_type::const_iterator it_end (e1 ().end ());
|
Chris@16
|
411 while (it != it_end) {
|
Chris@16
|
412 v.plus_assign (*it * row (e2 (), it.index ()));
|
Chris@16
|
413 ++ it;
|
Chris@16
|
414 }
|
Chris@16
|
415 return v;
|
Chris@16
|
416 }
|
Chris@16
|
417
|
Chris@16
|
418 // Dispatcher
|
Chris@16
|
419 template<class V, class E1, class E2>
|
Chris@16
|
420 BOOST_UBLAS_INLINE
|
Chris@16
|
421 V &
|
Chris@16
|
422 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
423 const matrix_expression<E2> &e2,
|
Chris@16
|
424 V &v, packed_random_access_iterator_tag) {
|
Chris@16
|
425 typedef typename E2::orientation_category orientation_category;
|
Chris@16
|
426 return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
|
Chris@16
|
427 }
|
Chris@16
|
428
|
Chris@16
|
429
|
Chris@16
|
430 /** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
|
Chris@16
|
431 optimized fashion.
|
Chris@16
|
432
|
Chris@16
|
433 \param e1 the vector expression \c x
|
Chris@16
|
434 \param e2 the matrix expression \c A
|
Chris@16
|
435 \param v the result vector \c v
|
Chris@16
|
436 \param init a boolean parameter
|
Chris@16
|
437
|
Chris@16
|
438 <tt>axpy_prod(x, A, v, init)</tt> implements the well known
|
Chris@16
|
439 axpy-product. Setting \a init to \c true is equivalent to call
|
Chris@16
|
440 <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
|
Chris@16
|
441 defaults to \c true, but this may change in the future.
|
Chris@16
|
442
|
Chris@16
|
443 Up to now there are some specialisation for compressed
|
Chris@16
|
444 matrices that give a large speed up compared to prod.
|
Chris@16
|
445
|
Chris@16
|
446 \ingroup blas2
|
Chris@16
|
447
|
Chris@16
|
448 \internal
|
Chris@16
|
449
|
Chris@16
|
450 template parameters:
|
Chris@16
|
451 \param V type of the result vector \c v
|
Chris@16
|
452 \param E1 type of a vector expression \c x
|
Chris@16
|
453 \param E2 type of a matrix expression \c A
|
Chris@16
|
454 */
|
Chris@16
|
455 template<class V, class E1, class E2>
|
Chris@16
|
456 BOOST_UBLAS_INLINE
|
Chris@16
|
457 V &
|
Chris@16
|
458 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
459 const matrix_expression<E2> &e2,
|
Chris@16
|
460 V &v, bool init = true) {
|
Chris@16
|
461 typedef typename V::value_type value_type;
|
Chris@16
|
462 typedef typename E1::const_iterator::iterator_category iterator_category;
|
Chris@16
|
463
|
Chris@16
|
464 if (init)
|
Chris@16
|
465 v.assign (zero_vector<value_type> (e2 ().size2 ()));
|
Chris@16
|
466 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
467 vector<value_type> cv (v);
|
Chris@16
|
468 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
469 real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
470 indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
Chris@16
|
471 #endif
|
Chris@16
|
472 axpy_prod (e1, e2, v, iterator_category ());
|
Chris@16
|
473 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
474 BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
Chris@16
|
475 #endif
|
Chris@16
|
476 return v;
|
Chris@16
|
477 }
|
Chris@16
|
478 template<class V, class E1, class E2>
|
Chris@16
|
479 BOOST_UBLAS_INLINE
|
Chris@16
|
480 V
|
Chris@16
|
481 axpy_prod (const vector_expression<E1> &e1,
|
Chris@16
|
482 const matrix_expression<E2> &e2) {
|
Chris@16
|
483 typedef V vector_type;
|
Chris@16
|
484
|
Chris@16
|
485 vector_type v (e2 ().size2 ());
|
Chris@16
|
486 return axpy_prod (e1, e2, v, true);
|
Chris@16
|
487 }
|
Chris@16
|
488
|
Chris@16
|
489 template<class M, class E1, class E2, class TRI>
|
Chris@16
|
490 BOOST_UBLAS_INLINE
|
Chris@16
|
491 M &
|
Chris@16
|
492 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
493 const matrix_expression<E2> &e2,
|
Chris@16
|
494 M &m, TRI,
|
Chris@16
|
495 dense_proxy_tag, row_major_tag) {
|
Chris@101
|
496
|
Chris@16
|
497 typedef typename M::size_type size_type;
|
Chris@16
|
498
|
Chris@16
|
499 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@101
|
500 typedef typename M::value_type value_type;
|
Chris@16
|
501 matrix<value_type, row_major> cm (m);
|
Chris@16
|
502 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
503 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
504 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
|
Chris@16
|
505 #endif
|
Chris@16
|
506 size_type size1 (e1 ().size1 ());
|
Chris@16
|
507 size_type size2 (e1 ().size2 ());
|
Chris@16
|
508 for (size_type i = 0; i < size1; ++ i)
|
Chris@16
|
509 for (size_type j = 0; j < size2; ++ j)
|
Chris@16
|
510 row (m, i).plus_assign (e1 () (i, j) * row (e2 (), j));
|
Chris@16
|
511 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
512 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
Chris@16
|
513 #endif
|
Chris@16
|
514 return m;
|
Chris@16
|
515 }
|
Chris@16
|
516 template<class M, class E1, class E2, class TRI>
|
Chris@16
|
517 BOOST_UBLAS_INLINE
|
Chris@16
|
518 M &
|
Chris@16
|
519 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
520 const matrix_expression<E2> &e2,
|
Chris@16
|
521 M &m, TRI,
|
Chris@16
|
522 sparse_proxy_tag, row_major_tag) {
|
Chris@101
|
523
|
Chris@16
|
524 typedef TRI triangular_restriction;
|
Chris@16
|
525 typedef const E1 expression1_type;
|
Chris@16
|
526 typedef const E2 expression2_type;
|
Chris@16
|
527
|
Chris@16
|
528 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@101
|
529 typedef typename M::value_type value_type;
|
Chris@16
|
530 matrix<value_type, row_major> cm (m);
|
Chris@16
|
531 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
532 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
533 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
|
Chris@16
|
534 #endif
|
Chris@16
|
535 typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
|
Chris@16
|
536 typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
|
Chris@16
|
537 while (it1 != it1_end) {
|
Chris@16
|
538 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
Chris@16
|
539 typename expression1_type::const_iterator2 it2 (it1.begin ());
|
Chris@16
|
540 typename expression1_type::const_iterator2 it2_end (it1.end ());
|
Chris@16
|
541 #else
|
Chris@16
|
542 typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
|
Chris@16
|
543 typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
|
Chris@16
|
544 #endif
|
Chris@16
|
545 while (it2 != it2_end) {
|
Chris@16
|
546 // row (m, it1.index1 ()).plus_assign (*it2 * row (e2 (), it2.index2 ()));
|
Chris@16
|
547 matrix_row<expression2_type> mr (e2 (), it2.index2 ());
|
Chris@16
|
548 typename matrix_row<expression2_type>::const_iterator itr (mr.begin ());
|
Chris@16
|
549 typename matrix_row<expression2_type>::const_iterator itr_end (mr.end ());
|
Chris@16
|
550 while (itr != itr_end) {
|
Chris@16
|
551 if (triangular_restriction::other (it1.index1 (), itr.index ()))
|
Chris@16
|
552 m (it1.index1 (), itr.index ()) += *it2 * *itr;
|
Chris@16
|
553 ++ itr;
|
Chris@16
|
554 }
|
Chris@16
|
555 ++ it2;
|
Chris@16
|
556 }
|
Chris@16
|
557 ++ it1;
|
Chris@16
|
558 }
|
Chris@16
|
559 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
560 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
Chris@16
|
561 #endif
|
Chris@16
|
562 return m;
|
Chris@16
|
563 }
|
Chris@16
|
564
|
Chris@16
|
565 template<class M, class E1, class E2, class TRI>
|
Chris@16
|
566 BOOST_UBLAS_INLINE
|
Chris@16
|
567 M &
|
Chris@16
|
568 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
569 const matrix_expression<E2> &e2,
|
Chris@16
|
570 M &m, TRI,
|
Chris@16
|
571 dense_proxy_tag, column_major_tag) {
|
Chris@16
|
572 typedef typename M::size_type size_type;
|
Chris@16
|
573
|
Chris@16
|
574 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@101
|
575 typedef typename M::value_type value_type;
|
Chris@16
|
576 matrix<value_type, column_major> cm (m);
|
Chris@16
|
577 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
578 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
579 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
|
Chris@16
|
580 #endif
|
Chris@16
|
581 size_type size1 (e2 ().size1 ());
|
Chris@16
|
582 size_type size2 (e2 ().size2 ());
|
Chris@16
|
583 for (size_type j = 0; j < size2; ++ j)
|
Chris@16
|
584 for (size_type i = 0; i < size1; ++ i)
|
Chris@16
|
585 column (m, j).plus_assign (e2 () (i, j) * column (e1 (), i));
|
Chris@16
|
586 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
587 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
Chris@16
|
588 #endif
|
Chris@16
|
589 return m;
|
Chris@16
|
590 }
|
Chris@16
|
591 template<class M, class E1, class E2, class TRI>
|
Chris@16
|
592 BOOST_UBLAS_INLINE
|
Chris@16
|
593 M &
|
Chris@16
|
594 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
595 const matrix_expression<E2> &e2,
|
Chris@16
|
596 M &m, TRI,
|
Chris@16
|
597 sparse_proxy_tag, column_major_tag) {
|
Chris@16
|
598 typedef TRI triangular_restriction;
|
Chris@16
|
599 typedef const E1 expression1_type;
|
Chris@16
|
600 typedef const E2 expression2_type;
|
Chris@101
|
601
|
Chris@16
|
602
|
Chris@16
|
603 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@101
|
604 typedef typename M::value_type value_type;
|
Chris@16
|
605 matrix<value_type, column_major> cm (m);
|
Chris@16
|
606 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
607 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
608 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
|
Chris@16
|
609 #endif
|
Chris@16
|
610 typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
|
Chris@16
|
611 typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
|
Chris@16
|
612 while (it2 != it2_end) {
|
Chris@16
|
613 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
Chris@16
|
614 typename expression2_type::const_iterator1 it1 (it2.begin ());
|
Chris@16
|
615 typename expression2_type::const_iterator1 it1_end (it2.end ());
|
Chris@16
|
616 #else
|
Chris@16
|
617 typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
|
Chris@16
|
618 typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
|
Chris@16
|
619 #endif
|
Chris@16
|
620 while (it1 != it1_end) {
|
Chris@16
|
621 // column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
|
Chris@16
|
622 matrix_column<expression1_type> mc (e1 (), it1.index1 ());
|
Chris@16
|
623 typename matrix_column<expression1_type>::const_iterator itc (mc.begin ());
|
Chris@16
|
624 typename matrix_column<expression1_type>::const_iterator itc_end (mc.end ());
|
Chris@16
|
625 while (itc != itc_end) {
|
Chris@16
|
626 if(triangular_restriction::other (itc.index (), it2.index2 ()))
|
Chris@16
|
627 m (itc.index (), it2.index2 ()) += *it1 * *itc;
|
Chris@16
|
628 ++ itc;
|
Chris@16
|
629 }
|
Chris@16
|
630 ++ it1;
|
Chris@16
|
631 }
|
Chris@16
|
632 ++ it2;
|
Chris@16
|
633 }
|
Chris@16
|
634 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
635 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
Chris@16
|
636 #endif
|
Chris@16
|
637 return m;
|
Chris@16
|
638 }
|
Chris@16
|
639
|
Chris@16
|
640 // Dispatcher
|
Chris@16
|
641 template<class M, class E1, class E2, class TRI>
|
Chris@16
|
642 BOOST_UBLAS_INLINE
|
Chris@16
|
643 M &
|
Chris@16
|
644 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
645 const matrix_expression<E2> &e2,
|
Chris@16
|
646 M &m, TRI, bool init = true) {
|
Chris@16
|
647 typedef typename M::value_type value_type;
|
Chris@16
|
648 typedef typename M::storage_category storage_category;
|
Chris@16
|
649 typedef typename M::orientation_category orientation_category;
|
Chris@16
|
650 typedef TRI triangular_restriction;
|
Chris@16
|
651
|
Chris@16
|
652 if (init)
|
Chris@16
|
653 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
Chris@16
|
654 return axpy_prod (e1, e2, m, triangular_restriction (), storage_category (), orientation_category ());
|
Chris@16
|
655 }
|
Chris@16
|
656 template<class M, class E1, class E2, class TRI>
|
Chris@16
|
657 BOOST_UBLAS_INLINE
|
Chris@16
|
658 M
|
Chris@16
|
659 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
660 const matrix_expression<E2> &e2,
|
Chris@16
|
661 TRI) {
|
Chris@16
|
662 typedef M matrix_type;
|
Chris@16
|
663 typedef TRI triangular_restriction;
|
Chris@16
|
664
|
Chris@16
|
665 matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
Chris@16
|
666 return axpy_prod (e1, e2, m, triangular_restriction (), true);
|
Chris@16
|
667 }
|
Chris@16
|
668
|
Chris@16
|
669 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
|
Chris@16
|
670 optimized fashion.
|
Chris@16
|
671
|
Chris@16
|
672 \param e1 the matrix expression \c A
|
Chris@16
|
673 \param e2 the matrix expression \c X
|
Chris@16
|
674 \param m the result matrix \c M
|
Chris@16
|
675 \param init a boolean parameter
|
Chris@16
|
676
|
Chris@16
|
677 <tt>axpy_prod(A, X, M, init)</tt> implements the well known
|
Chris@16
|
678 axpy-product. Setting \a init to \c true is equivalent to call
|
Chris@16
|
679 <tt>M.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
|
Chris@16
|
680 defaults to \c true, but this may change in the future.
|
Chris@16
|
681
|
Chris@16
|
682 Up to now there are no specialisations.
|
Chris@16
|
683
|
Chris@16
|
684 \ingroup blas3
|
Chris@16
|
685
|
Chris@16
|
686 \internal
|
Chris@16
|
687
|
Chris@16
|
688 template parameters:
|
Chris@16
|
689 \param M type of the result matrix \c M
|
Chris@16
|
690 \param E1 type of a matrix expression \c A
|
Chris@16
|
691 \param E2 type of a matrix expression \c X
|
Chris@16
|
692 */
|
Chris@16
|
693 template<class M, class E1, class E2>
|
Chris@16
|
694 BOOST_UBLAS_INLINE
|
Chris@16
|
695 M &
|
Chris@16
|
696 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
697 const matrix_expression<E2> &e2,
|
Chris@16
|
698 M &m, bool init = true) {
|
Chris@16
|
699 typedef typename M::value_type value_type;
|
Chris@16
|
700 typedef typename M::storage_category storage_category;
|
Chris@16
|
701 typedef typename M::orientation_category orientation_category;
|
Chris@16
|
702
|
Chris@16
|
703 if (init)
|
Chris@16
|
704 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
Chris@16
|
705 return axpy_prod (e1, e2, m, full (), storage_category (), orientation_category ());
|
Chris@16
|
706 }
|
Chris@16
|
707 template<class M, class E1, class E2>
|
Chris@16
|
708 BOOST_UBLAS_INLINE
|
Chris@16
|
709 M
|
Chris@16
|
710 axpy_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
711 const matrix_expression<E2> &e2) {
|
Chris@16
|
712 typedef M matrix_type;
|
Chris@16
|
713
|
Chris@16
|
714 matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
Chris@16
|
715 return axpy_prod (e1, e2, m, full (), true);
|
Chris@16
|
716 }
|
Chris@16
|
717
|
Chris@16
|
718
|
Chris@16
|
719 template<class M, class E1, class E2>
|
Chris@16
|
720 BOOST_UBLAS_INLINE
|
Chris@16
|
721 M &
|
Chris@16
|
722 opb_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
723 const matrix_expression<E2> &e2,
|
Chris@16
|
724 M &m,
|
Chris@16
|
725 dense_proxy_tag, row_major_tag) {
|
Chris@16
|
726 typedef typename M::size_type size_type;
|
Chris@16
|
727 typedef typename M::value_type value_type;
|
Chris@16
|
728
|
Chris@16
|
729 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
730 matrix<value_type, row_major> cm (m);
|
Chris@16
|
731 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
732 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
733 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
|
Chris@16
|
734 #endif
|
Chris@16
|
735 size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
|
Chris@16
|
736 for (size_type k = 0; k < size; ++ k) {
|
Chris@16
|
737 vector<value_type> ce1 (column (e1 (), k));
|
Chris@16
|
738 vector<value_type> re2 (row (e2 (), k));
|
Chris@16
|
739 m.plus_assign (outer_prod (ce1, re2));
|
Chris@16
|
740 }
|
Chris@16
|
741 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
742 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
Chris@16
|
743 #endif
|
Chris@16
|
744 return m;
|
Chris@16
|
745 }
|
Chris@16
|
746
|
Chris@16
|
747 template<class M, class E1, class E2>
|
Chris@16
|
748 BOOST_UBLAS_INLINE
|
Chris@16
|
749 M &
|
Chris@16
|
750 opb_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
751 const matrix_expression<E2> &e2,
|
Chris@16
|
752 M &m,
|
Chris@16
|
753 dense_proxy_tag, column_major_tag) {
|
Chris@16
|
754 typedef typename M::size_type size_type;
|
Chris@16
|
755 typedef typename M::value_type value_type;
|
Chris@16
|
756
|
Chris@16
|
757 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
758 matrix<value_type, column_major> cm (m);
|
Chris@16
|
759 typedef typename type_traits<value_type>::real_type real_type;
|
Chris@16
|
760 real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
Chris@16
|
761 indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
|
Chris@16
|
762 #endif
|
Chris@16
|
763 size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
|
Chris@16
|
764 for (size_type k = 0; k < size; ++ k) {
|
Chris@16
|
765 vector<value_type> ce1 (column (e1 (), k));
|
Chris@16
|
766 vector<value_type> re2 (row (e2 (), k));
|
Chris@16
|
767 m.plus_assign (outer_prod (ce1, re2));
|
Chris@16
|
768 }
|
Chris@16
|
769 #if BOOST_UBLAS_TYPE_CHECK
|
Chris@16
|
770 BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
Chris@16
|
771 #endif
|
Chris@16
|
772 return m;
|
Chris@16
|
773 }
|
Chris@16
|
774
|
Chris@16
|
775 // Dispatcher
|
Chris@16
|
776
|
Chris@16
|
777 /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
|
Chris@16
|
778 optimized fashion.
|
Chris@16
|
779
|
Chris@16
|
780 \param e1 the matrix expression \c A
|
Chris@16
|
781 \param e2 the matrix expression \c X
|
Chris@16
|
782 \param m the result matrix \c M
|
Chris@16
|
783 \param init a boolean parameter
|
Chris@16
|
784
|
Chris@16
|
785 <tt>opb_prod(A, X, M, init)</tt> implements the well known
|
Chris@16
|
786 axpy-product. Setting \a init to \c true is equivalent to call
|
Chris@16
|
787 <tt>M.clear()</tt> before <tt>opb_prod</tt>. Currently \a init
|
Chris@16
|
788 defaults to \c true, but this may change in the future.
|
Chris@16
|
789
|
Chris@16
|
790 This function may give a speedup if \c A has less columns than
|
Chris@16
|
791 rows, because the product is computed as a sum of outer
|
Chris@16
|
792 products.
|
Chris@16
|
793
|
Chris@16
|
794 \ingroup blas3
|
Chris@16
|
795
|
Chris@16
|
796 \internal
|
Chris@16
|
797
|
Chris@16
|
798 template parameters:
|
Chris@16
|
799 \param M type of the result matrix \c M
|
Chris@16
|
800 \param E1 type of a matrix expression \c A
|
Chris@16
|
801 \param E2 type of a matrix expression \c X
|
Chris@16
|
802 */
|
Chris@16
|
803 template<class M, class E1, class E2>
|
Chris@16
|
804 BOOST_UBLAS_INLINE
|
Chris@16
|
805 M &
|
Chris@16
|
806 opb_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
807 const matrix_expression<E2> &e2,
|
Chris@16
|
808 M &m, bool init = true) {
|
Chris@16
|
809 typedef typename M::value_type value_type;
|
Chris@16
|
810 typedef typename M::storage_category storage_category;
|
Chris@16
|
811 typedef typename M::orientation_category orientation_category;
|
Chris@16
|
812
|
Chris@16
|
813 if (init)
|
Chris@16
|
814 m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
Chris@16
|
815 return opb_prod (e1, e2, m, storage_category (), orientation_category ());
|
Chris@16
|
816 }
|
Chris@16
|
817 template<class M, class E1, class E2>
|
Chris@16
|
818 BOOST_UBLAS_INLINE
|
Chris@16
|
819 M
|
Chris@16
|
820 opb_prod (const matrix_expression<E1> &e1,
|
Chris@16
|
821 const matrix_expression<E2> &e2) {
|
Chris@16
|
822 typedef M matrix_type;
|
Chris@16
|
823
|
Chris@16
|
824 matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
Chris@16
|
825 return opb_prod (e1, e2, m, true);
|
Chris@16
|
826 }
|
Chris@16
|
827
|
Chris@16
|
828 }}}
|
Chris@16
|
829
|
Chris@16
|
830 #endif
|