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_VECTOR_ASSIGN_
14 #define _BOOST_UBLAS_VECTOR_ASSIGN_
16 #include <boost/numeric/ublas/functional.hpp> // scalar_assign
17 // Required for make_conformant storage
20 // Iterators based on ideas of Jeremy Siek
22 namespace boost { namespace numeric { namespace ublas {
25 // Weak equality check - useful to compare equality two arbitary vector expression results.
26 // Since the actual expressions are unknown, we check for and arbitary error bound
27 // on the relative error.
28 // For a linear expression the infinity norm makes sense as we do not know how the elements will be
29 // combined in the expression. False positive results are inevitable for arbirary expressions!
30 template<class E1, class E2, class S>
32 bool equals (const vector_expression<E1> &e1, const vector_expression<E2> &e2, S epsilon, S min_norm) {
33 return norm_inf (e1 - e2) <= epsilon *
34 std::max<S> (std::max<S> (norm_inf (e1), norm_inf (e2)), min_norm);
37 template<class E1, class E2>
39 bool expression_type_check (const vector_expression<E1> &e1, const vector_expression<E2> &e2) {
40 typedef typename type_traits<typename promote_traits<typename E1::value_type,
41 typename E2::value_type>::promote_type>::real_type real_type;
42 return equals (e1, e2, BOOST_UBLAS_TYPE_CHECK_EPSILON, BOOST_UBLAS_TYPE_CHECK_MIN);
46 // Make sparse proxies conformant
47 template<class V, class E>
48 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
49 void make_conformant (V &v, const vector_expression<E> &e) {
50 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
51 typedef typename V::size_type size_type;
52 typedef typename V::difference_type difference_type;
53 typedef typename V::value_type value_type;
54 // FIXME unbounded_array with push_back maybe better
55 std::vector<size_type> index;
56 typename V::iterator it (v.begin ());
57 typename V::iterator it_end (v.end ());
58 typename E::const_iterator ite (e ().begin ());
59 typename E::const_iterator ite_end (e ().end ());
60 if (it != it_end && ite != ite_end) {
61 size_type it_index = it.index (), ite_index = ite.index ();
63 difference_type compare = it_index - ite_index;
66 if (it != it_end && ite != ite_end) {
67 it_index = it.index ();
68 ite_index = ite.index ();
71 } else if (compare < 0) {
72 increment (it, it_end, - compare);
74 it_index = it.index ();
77 } else if (compare > 0) {
78 if (*ite != value_type/*zero*/())
79 index.push_back (ite.index ());
82 ite_index = ite.index ();
89 while (ite != ite_end) {
90 if (*ite != value_type/*zero*/())
91 index.push_back (ite.index ());
94 for (size_type k = 0; k < index.size (); ++ k)
95 v (index [k]) = value_type/*zero*/();
101 // Explicitly iterating
102 template<template <class T1, class T2> class F, class V, class T>
103 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
104 void iterating_vector_assign_scalar (V &v, const T &t) {
105 typedef F<typename V::iterator::reference, T> functor_type;
106 typedef typename V::difference_type difference_type;
107 difference_type size (v.size ());
108 typename V::iterator it (v.begin ());
109 BOOST_UBLAS_CHECK (v.end () - it == size, bad_size ());
110 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
112 functor_type::apply (*it, t), ++ it;
114 DD (size, 4, r, (functor_type::apply (*it, t), ++ it));
118 template<template <class T1, class T2> class F, class V, class T>
119 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
120 void indexing_vector_assign_scalar (V &v, const T &t) {
121 typedef F<typename V::reference, T> functor_type;
122 typedef typename V::size_type size_type;
123 size_type size (v.size ());
124 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
125 for (size_type i = 0; i < size; ++ i)
126 functor_type::apply (v (i), t);
129 DD (size, 4, r, (functor_type::apply (v (i), t), ++ i));
133 // Dense (proxy) case
134 template<template <class T1, class T2> class F, class V, class T>
135 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
136 void vector_assign_scalar (V &v, const T &t, dense_proxy_tag) {
137 #ifdef BOOST_UBLAS_USE_INDEXING
138 indexing_vector_assign_scalar<F> (v, t);
139 #elif BOOST_UBLAS_USE_ITERATING
140 iterating_vector_assign_scalar<F> (v, t);
142 typedef typename V::size_type size_type;
143 size_type size (v.size ());
144 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
145 iterating_vector_assign_scalar<F> (v, t);
147 indexing_vector_assign_scalar<F> (v, t);
150 // Packed (proxy) case
151 template<template <class T1, class T2> class F, class V, class T>
152 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
153 void vector_assign_scalar (V &v, const T &t, packed_proxy_tag) {
154 typedef F<typename V::iterator::reference, T> functor_type;
155 typedef typename V::difference_type difference_type;
156 typename V::iterator it (v.begin ());
157 difference_type size (v.end () - it);
159 functor_type::apply (*it, t), ++ it;
161 // Sparse (proxy) case
162 template<template <class T1, class T2> class F, class V, class T>
163 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
164 void vector_assign_scalar (V &v, const T &t, sparse_proxy_tag) {
165 typedef F<typename V::iterator::reference, T> functor_type;
166 typename V::iterator it (v.begin ());
167 typename V::iterator it_end (v.end ());
169 functor_type::apply (*it, t), ++ it;
173 template<template <class T1, class T2> class F, class V, class T>
175 void vector_assign_scalar (V &v, const T &t) {
176 typedef typename V::storage_category storage_category;
177 vector_assign_scalar<F> (v, t, storage_category ());
180 template<class SC, bool COMPUTED, class RI>
181 struct vector_assign_traits {
182 typedef SC storage_category;
185 template<bool COMPUTED>
186 struct vector_assign_traits<dense_tag, COMPUTED, packed_random_access_iterator_tag> {
187 typedef packed_tag storage_category;
190 struct vector_assign_traits<dense_tag, false, sparse_bidirectional_iterator_tag> {
191 typedef sparse_tag storage_category;
194 struct vector_assign_traits<dense_tag, true, sparse_bidirectional_iterator_tag> {
195 typedef sparse_proxy_tag storage_category;
198 template<bool COMPUTED>
199 struct vector_assign_traits<dense_proxy_tag, COMPUTED, packed_random_access_iterator_tag> {
200 typedef packed_proxy_tag storage_category;
203 struct vector_assign_traits<dense_proxy_tag, false, sparse_bidirectional_iterator_tag> {
204 typedef sparse_proxy_tag storage_category;
207 struct vector_assign_traits<dense_proxy_tag, true, sparse_bidirectional_iterator_tag> {
208 typedef sparse_proxy_tag storage_category;
212 struct vector_assign_traits<packed_tag, false, sparse_bidirectional_iterator_tag> {
213 typedef sparse_tag storage_category;
216 struct vector_assign_traits<packed_tag, true, sparse_bidirectional_iterator_tag> {
217 typedef sparse_proxy_tag storage_category;
220 template<bool COMPUTED>
221 struct vector_assign_traits<packed_proxy_tag, COMPUTED, sparse_bidirectional_iterator_tag> {
222 typedef sparse_proxy_tag storage_category;
226 struct vector_assign_traits<sparse_tag, true, dense_random_access_iterator_tag> {
227 typedef sparse_proxy_tag storage_category;
230 struct vector_assign_traits<sparse_tag, true, packed_random_access_iterator_tag> {
231 typedef sparse_proxy_tag storage_category;
234 struct vector_assign_traits<sparse_tag, true, sparse_bidirectional_iterator_tag> {
235 typedef sparse_proxy_tag storage_category;
238 // Explicitly iterating
239 template<template <class T1, class T2> class F, class V, class E>
240 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
241 void iterating_vector_assign (V &v, const vector_expression<E> &e) {
242 typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
243 typedef typename V::difference_type difference_type;
244 difference_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
245 typename V::iterator it (v.begin ());
246 BOOST_UBLAS_CHECK (v.end () - it == size, bad_size ());
247 typename E::const_iterator ite (e ().begin ());
248 BOOST_UBLAS_CHECK (e ().end () - ite == size, bad_size ());
249 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
251 functor_type::apply (*it, *ite), ++ it, ++ ite;
253 DD (size, 2, r, (functor_type::apply (*it, *ite), ++ it, ++ ite));
256 // Explicitly indexing
257 template<template <class T1, class T2> class F, class V, class E>
258 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
259 void indexing_vector_assign (V &v, const vector_expression<E> &e) {
260 typedef F<typename V::reference, typename E::value_type> functor_type;
261 typedef typename V::size_type size_type;
262 size_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
263 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
264 for (size_type i = 0; i < size; ++ i)
265 functor_type::apply (v (i), e () (i));
268 DD (size, 2, r, (functor_type::apply (v (i), e () (i)), ++ i));
272 // Dense (proxy) case
273 template<template <class T1, class T2> class F, class V, class E>
274 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
275 void vector_assign (V &v, const vector_expression<E> &e, dense_proxy_tag) {
276 #ifdef BOOST_UBLAS_USE_INDEXING
277 indexing_vector_assign<F> (v, e);
278 #elif BOOST_UBLAS_USE_ITERATING
279 iterating_vector_assign<F> (v, e);
281 typedef typename V::size_type size_type;
282 size_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
283 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
284 iterating_vector_assign<F> (v, e);
286 indexing_vector_assign<F> (v, e);
289 // Packed (proxy) case
290 template<template <class T1, class T2> class F, class V, class E>
291 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
292 void vector_assign (V &v, const vector_expression<E> &e, packed_proxy_tag) {
293 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
294 typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
295 typedef typename V::difference_type difference_type;
296 typedef typename V::value_type value_type;
297 #if BOOST_UBLAS_TYPE_CHECK
298 vector<value_type> cv (v.size ());
299 indexing_vector_assign<scalar_assign> (cv, v);
300 indexing_vector_assign<F> (cv, e);
302 typename V::iterator it (v.begin ());
303 typename V::iterator it_end (v.end ());
304 typename E::const_iterator ite (e ().begin ());
305 typename E::const_iterator ite_end (e ().end ());
306 difference_type it_size (it_end - it);
307 difference_type ite_size (ite_end - ite);
308 if (it_size > 0 && ite_size > 0) {
309 difference_type size ((std::min) (difference_type (it.index () - ite.index ()), ite_size));
315 if (it_size > 0 && ite_size > 0) {
316 difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
319 if (!functor_type::computed) {
320 while (-- size >= 0) // zeroing
321 functor_type::apply (*it, value_type/*zero*/()), ++ it;
327 difference_type size ((std::min) (it_size, ite_size));
331 functor_type::apply (*it, *ite), ++ it, ++ ite;
333 if (!functor_type::computed) {
334 while (-- size >= 0) // zeroing
335 functor_type::apply (*it, value_type/*zero*/()), ++ it;
339 #if BOOST_UBLAS_TYPE_CHECK
340 if (! disable_type_check<bool>::value)
341 BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
342 external_logic ("external logic or bad condition of inputs"));
346 template<template <class T1, class T2> class F, class V, class E>
347 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
348 void vector_assign (V &v, const vector_expression<E> &e, sparse_tag) {
349 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
350 typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
351 BOOST_STATIC_ASSERT ((!functor_type::computed));
352 typedef typename V::value_type value_type;
353 #if BOOST_UBLAS_TYPE_CHECK
354 vector<value_type> cv (v.size ());
355 indexing_vector_assign<scalar_assign> (cv, v);
356 indexing_vector_assign<F> (cv, e);
359 typename E::const_iterator ite (e ().begin ());
360 typename E::const_iterator ite_end (e ().end ());
361 while (ite != ite_end) {
363 if (t != value_type/*zero*/())
364 v.insert_element (ite.index (), t);
367 #if BOOST_UBLAS_TYPE_CHECK
368 if (! disable_type_check<bool>::value)
369 BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
370 external_logic ("external logic or bad condition of inputs"));
373 // Sparse proxy or functional case
374 template<template <class T1, class T2> class F, class V, class E>
375 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
376 void vector_assign (V &v, const vector_expression<E> &e, sparse_proxy_tag) {
377 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
378 typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
379 typedef typename V::size_type size_type;
380 typedef typename V::difference_type difference_type;
381 typedef typename V::value_type value_type;
383 #if BOOST_UBLAS_TYPE_CHECK
384 vector<value_type> cv (v.size ());
385 indexing_vector_assign<scalar_assign> (cv, v);
386 indexing_vector_assign<F> (cv, e);
388 detail::make_conformant (v, e);
390 typename V::iterator it (v.begin ());
391 typename V::iterator it_end (v.end ());
392 typename E::const_iterator ite (e ().begin ());
393 typename E::const_iterator ite_end (e ().end ());
394 if (it != it_end && ite != ite_end) {
395 size_type it_index = it.index (), ite_index = ite.index ();
397 difference_type compare = it_index - ite_index;
399 functor_type::apply (*it, *ite);
401 if (it != it_end && ite != ite_end) {
402 it_index = it.index ();
403 ite_index = ite.index ();
406 } else if (compare < 0) {
407 if (!functor_type::computed) {
408 functor_type::apply (*it, value_type/*zero*/());
411 increment (it, it_end, - compare);
413 it_index = it.index ();
416 } else if (compare > 0) {
417 increment (ite, ite_end, compare);
419 ite_index = ite.index ();
426 if (!functor_type::computed) {
427 while (it != it_end) { // zeroing
428 functor_type::apply (*it, value_type/*zero*/());
434 #if BOOST_UBLAS_TYPE_CHECK
435 if (! disable_type_check<bool>::value)
436 BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
437 external_logic ("external logic or bad condition of inputs"));
442 template<template <class T1, class T2> class F, class V, class E>
444 void vector_assign (V &v, const vector_expression<E> &e) {
445 typedef typename vector_assign_traits<typename V::storage_category,
446 F<typename V::reference, typename E::value_type>::computed,
447 typename E::const_iterator::iterator_category>::storage_category storage_category;
448 vector_assign<F> (v, e, storage_category ());
451 template<class SC, class RI>
452 struct vector_swap_traits {
453 typedef SC storage_category;
457 struct vector_swap_traits<dense_proxy_tag, sparse_bidirectional_iterator_tag> {
458 typedef sparse_proxy_tag storage_category;
462 struct vector_swap_traits<packed_proxy_tag, sparse_bidirectional_iterator_tag> {
463 typedef sparse_proxy_tag storage_category;
466 // Dense (proxy) case
467 template<template <class T1, class T2> class F, class V, class E>
468 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
469 void vector_swap (V &v, vector_expression<E> &e, dense_proxy_tag) {
470 typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
471 typedef typename V::difference_type difference_type;
472 difference_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
473 typename V::iterator it (v.begin ());
474 typename E::iterator ite (e ().begin ());
476 functor_type::apply (*it, *ite), ++ it, ++ ite;
478 // Packed (proxy) case
479 template<template <class T1, class T2> class F, class V, class E>
480 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
481 void vector_swap (V &v, vector_expression<E> &e, packed_proxy_tag) {
482 typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
483 typedef typename V::difference_type difference_type;
484 typename V::iterator it (v.begin ());
485 typename V::iterator it_end (v.end ());
486 typename E::iterator ite (e ().begin ());
487 typename E::iterator ite_end (e ().end ());
488 difference_type it_size (it_end - it);
489 difference_type ite_size (ite_end - ite);
490 if (it_size > 0 && ite_size > 0) {
491 difference_type size ((std::min) (difference_type (it.index () - ite.index ()), ite_size));
497 if (it_size > 0 && ite_size > 0) {
498 difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
502 difference_type size ((std::min) (it_size, ite_size));
506 functor_type::apply (*it, *ite), ++ it, ++ ite;
509 template<template <class T1, class T2> class F, class V, class E>
510 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
511 void vector_swap (V &v, vector_expression<E> &e, sparse_proxy_tag) {
512 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
513 typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
514 typedef typename V::size_type size_type;
515 typedef typename V::difference_type difference_type;
517 detail::make_conformant (v, e);
518 // FIXME should be a seperate restriction for E
519 detail::make_conformant (e (), v);
521 typename V::iterator it (v.begin ());
522 typename V::iterator it_end (v.end ());
523 typename E::iterator ite (e ().begin ());
524 typename E::iterator ite_end (e ().end ());
525 if (it != it_end && ite != ite_end) {
526 size_type it_index = it.index (), ite_index = ite.index ();
528 difference_type compare = it_index - ite_index;
530 functor_type::apply (*it, *ite);
532 if (it != it_end && ite != ite_end) {
533 it_index = it.index ();
534 ite_index = ite.index ();
537 } else if (compare < 0) {
538 increment (it, it_end, - compare);
540 it_index = it.index ();
543 } else if (compare > 0) {
544 increment (ite, ite_end, compare);
546 ite_index = ite.index ();
553 #if BOOST_UBLAS_TYPE_CHECK
554 increment (ite, ite_end);
555 increment (it, it_end);
560 template<template <class T1, class T2> class F, class V, class E>
562 void vector_swap (V &v, vector_expression<E> &e) {
563 typedef typename vector_swap_traits<typename V::storage_category,
564 typename E::const_iterator::iterator_category>::storage_category storage_category;
565 vector_swap<F> (v, e, storage_category ());