]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/numeric/ublas/include/boost/numeric/ublas/detail/vector_assign.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / numeric / ublas / include / boost / numeric / ublas / detail / vector_assign.hpp
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_VECTOR_ASSIGN_
14 #define _BOOST_UBLAS_VECTOR_ASSIGN_
15
16 #include <boost/numeric/ublas/functional.hpp> // scalar_assign
17 // Required for make_conformant storage
18 #include <vector>
19
20 // Iterators based on ideas of Jeremy Siek
21
22 namespace boost { namespace numeric { namespace ublas {
23 namespace detail {
24
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>
31 BOOST_UBLAS_INLINE
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);
35 }
36
37 template<class E1, class E2>
38 BOOST_UBLAS_INLINE
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);
43 }
44
45
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 ();
62 while (true) {
63 difference_type compare = it_index - ite_index;
64 if (compare == 0) {
65 ++ it, ++ ite;
66 if (it != it_end && ite != ite_end) {
67 it_index = it.index ();
68 ite_index = ite.index ();
69 } else
70 break;
71 } else if (compare < 0) {
72 increment (it, it_end, - compare);
73 if (it != it_end)
74 it_index = it.index ();
75 else
76 break;
77 } else if (compare > 0) {
78 if (*ite != value_type/*zero*/())
79 index.push_back (ite.index ());
80 ++ ite;
81 if (ite != ite_end)
82 ite_index = ite.index ();
83 else
84 break;
85 }
86 }
87 }
88
89 while (ite != ite_end) {
90 if (*ite != value_type/*zero*/())
91 index.push_back (ite.index ());
92 ++ ite;
93 }
94 for (size_type k = 0; k < index.size (); ++ k)
95 v (index [k]) = value_type/*zero*/();
96 }
97
98 }//namespace detail
99
100
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
111 while (-- size >= 0)
112 functor_type::apply (*it, t), ++ it;
113 #else
114 DD (size, 4, r, (functor_type::apply (*it, t), ++ it));
115 #endif
116 }
117 // Explicitly case
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);
127 #else
128 size_type i (0);
129 DD (size, 4, r, (functor_type::apply (v (i), t), ++ i));
130 #endif
131 }
132
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);
141 #else
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);
146 else
147 indexing_vector_assign_scalar<F> (v, t);
148 #endif
149 }
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);
158 while (-- size >= 0)
159 functor_type::apply (*it, t), ++ it;
160 }
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 ());
168 while (it != it_end)
169 functor_type::apply (*it, t), ++ it;
170 }
171
172 // Dispatcher
173 template<template <class T1, class T2> class F, class V, class T>
174 BOOST_UBLAS_INLINE
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 ());
178 }
179
180 template<class SC, bool COMPUTED, class RI>
181 struct vector_assign_traits {
182 typedef SC storage_category;
183 };
184
185 template<bool COMPUTED>
186 struct vector_assign_traits<dense_tag, COMPUTED, packed_random_access_iterator_tag> {
187 typedef packed_tag storage_category;
188 };
189 template<>
190 struct vector_assign_traits<dense_tag, false, sparse_bidirectional_iterator_tag> {
191 typedef sparse_tag storage_category;
192 };
193 template<>
194 struct vector_assign_traits<dense_tag, true, sparse_bidirectional_iterator_tag> {
195 typedef sparse_proxy_tag storage_category;
196 };
197
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;
201 };
202 template<>
203 struct vector_assign_traits<dense_proxy_tag, false, sparse_bidirectional_iterator_tag> {
204 typedef sparse_proxy_tag storage_category;
205 };
206 template<>
207 struct vector_assign_traits<dense_proxy_tag, true, sparse_bidirectional_iterator_tag> {
208 typedef sparse_proxy_tag storage_category;
209 };
210
211 template<>
212 struct vector_assign_traits<packed_tag, false, sparse_bidirectional_iterator_tag> {
213 typedef sparse_tag storage_category;
214 };
215 template<>
216 struct vector_assign_traits<packed_tag, true, sparse_bidirectional_iterator_tag> {
217 typedef sparse_proxy_tag storage_category;
218 };
219
220 template<bool COMPUTED>
221 struct vector_assign_traits<packed_proxy_tag, COMPUTED, sparse_bidirectional_iterator_tag> {
222 typedef sparse_proxy_tag storage_category;
223 };
224
225 template<>
226 struct vector_assign_traits<sparse_tag, true, dense_random_access_iterator_tag> {
227 typedef sparse_proxy_tag storage_category;
228 };
229 template<>
230 struct vector_assign_traits<sparse_tag, true, packed_random_access_iterator_tag> {
231 typedef sparse_proxy_tag storage_category;
232 };
233 template<>
234 struct vector_assign_traits<sparse_tag, true, sparse_bidirectional_iterator_tag> {
235 typedef sparse_proxy_tag storage_category;
236 };
237
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
250 while (-- size >= 0)
251 functor_type::apply (*it, *ite), ++ it, ++ ite;
252 #else
253 DD (size, 2, r, (functor_type::apply (*it, *ite), ++ it, ++ ite));
254 #endif
255 }
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));
266 #else
267 size_type i (0);
268 DD (size, 2, r, (functor_type::apply (v (i), e () (i)), ++ i));
269 #endif
270 }
271
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);
280 #else
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);
285 else
286 indexing_vector_assign<F> (v, e);
287 #endif
288 }
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);
301 #endif
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));
310 if (size > 0) {
311 ite += size;
312 ite_size -= size;
313 }
314 }
315 if (it_size > 0 && ite_size > 0) {
316 difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
317 if (size > 0) {
318 it_size -= size;
319 if (!functor_type::computed) {
320 while (-- size >= 0) // zeroing
321 functor_type::apply (*it, value_type/*zero*/()), ++ it;
322 } else {
323 it += size;
324 }
325 }
326 }
327 difference_type size ((std::min) (it_size, ite_size));
328 it_size -= size;
329 ite_size -= size;
330 while (-- size >= 0)
331 functor_type::apply (*it, *ite), ++ it, ++ ite;
332 size = it_size;
333 if (!functor_type::computed) {
334 while (-- size >= 0) // zeroing
335 functor_type::apply (*it, value_type/*zero*/()), ++ it;
336 } else {
337 it += size;
338 }
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"));
343 #endif
344 }
345 // Sparse case
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);
357 #endif
358 v.clear ();
359 typename E::const_iterator ite (e ().begin ());
360 typename E::const_iterator ite_end (e ().end ());
361 while (ite != ite_end) {
362 value_type t (*ite);
363 if (t != value_type/*zero*/())
364 v.insert_element (ite.index (), t);
365 ++ ite;
366 }
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"));
371 #endif
372 }
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;
382
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);
387 #endif
388 detail::make_conformant (v, e);
389
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 ();
396 while (true) {
397 difference_type compare = it_index - ite_index;
398 if (compare == 0) {
399 functor_type::apply (*it, *ite);
400 ++ it, ++ ite;
401 if (it != it_end && ite != ite_end) {
402 it_index = it.index ();
403 ite_index = ite.index ();
404 } else
405 break;
406 } else if (compare < 0) {
407 if (!functor_type::computed) {
408 functor_type::apply (*it, value_type/*zero*/());
409 ++ it;
410 } else
411 increment (it, it_end, - compare);
412 if (it != it_end)
413 it_index = it.index ();
414 else
415 break;
416 } else if (compare > 0) {
417 increment (ite, ite_end, compare);
418 if (ite != ite_end)
419 ite_index = ite.index ();
420 else
421 break;
422 }
423 }
424 }
425
426 if (!functor_type::computed) {
427 while (it != it_end) { // zeroing
428 functor_type::apply (*it, value_type/*zero*/());
429 ++ it;
430 }
431 } else {
432 it = it_end;
433 }
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"));
438 #endif
439 }
440
441 // Dispatcher
442 template<template <class T1, class T2> class F, class V, class E>
443 BOOST_UBLAS_INLINE
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 ());
449 }
450
451 template<class SC, class RI>
452 struct vector_swap_traits {
453 typedef SC storage_category;
454 };
455
456 template<>
457 struct vector_swap_traits<dense_proxy_tag, sparse_bidirectional_iterator_tag> {
458 typedef sparse_proxy_tag storage_category;
459 };
460
461 template<>
462 struct vector_swap_traits<packed_proxy_tag, sparse_bidirectional_iterator_tag> {
463 typedef sparse_proxy_tag storage_category;
464 };
465
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 ());
475 while (-- size >= 0)
476 functor_type::apply (*it, *ite), ++ it, ++ ite;
477 }
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));
492 if (size > 0) {
493 ite += size;
494 ite_size -= size;
495 }
496 }
497 if (it_size > 0 && ite_size > 0) {
498 difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
499 if (size > 0)
500 it_size -= size;
501 }
502 difference_type size ((std::min) (it_size, ite_size));
503 it_size -= size;
504 ite_size -= size;
505 while (-- size >= 0)
506 functor_type::apply (*it, *ite), ++ it, ++ ite;
507 }
508 // Sparse proxy case
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;
516
517 detail::make_conformant (v, e);
518 // FIXME should be a seperate restriction for E
519 detail::make_conformant (e (), v);
520
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 ();
527 while (true) {
528 difference_type compare = it_index - ite_index;
529 if (compare == 0) {
530 functor_type::apply (*it, *ite);
531 ++ it, ++ ite;
532 if (it != it_end && ite != ite_end) {
533 it_index = it.index ();
534 ite_index = ite.index ();
535 } else
536 break;
537 } else if (compare < 0) {
538 increment (it, it_end, - compare);
539 if (it != it_end)
540 it_index = it.index ();
541 else
542 break;
543 } else if (compare > 0) {
544 increment (ite, ite_end, compare);
545 if (ite != ite_end)
546 ite_index = ite.index ();
547 else
548 break;
549 }
550 }
551 }
552
553 #if BOOST_UBLAS_TYPE_CHECK
554 increment (ite, ite_end);
555 increment (it, it_end);
556 #endif
557 }
558
559 // Dispatcher
560 template<template <class T1, class T2> class F, class V, class E>
561 BOOST_UBLAS_INLINE
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 ());
566 }
567
568 }}}
569
570 #endif