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
22namespace boost { namespace numeric { namespace ublas {
23namespace 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 for (;;) {
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//Disabled warning C4127 because the conditional expression is constant
320#ifdef _MSC_VER
321#pragma warning(push)
322#pragma warning(disable: 4127)
323#endif
324 if (!functor_type::computed) {
325#ifdef _MSC_VER
326#pragma warning(pop)
327#endif
328 while (-- size >= 0) // zeroing
329 functor_type::apply (*it, value_type/*zero*/()), ++ it;
330 } else {
331 it += size;
332 }
333 }
334 }
335 difference_type size ((std::min) (it_size, ite_size));
336 it_size -= size;
337 ite_size -= size;
338 while (-- size >= 0)
339 functor_type::apply (*it, *ite), ++ it, ++ ite;
340 size = it_size;
341//Disabled warning C4127 because the conditional expression is constant
342#ifdef _MSC_VER
343#pragma warning(push)
344#pragma warning(disable: 4127)
345#endif
346 if (!functor_type::computed) {
347#ifdef _MSC_VER
348#pragma warning(pop)
349#endif
350 while (-- size >= 0) // zeroing
351 functor_type::apply (*it, value_type/*zero*/()), ++ it;
352 } else {
353 it += size;
354 }
355#if BOOST_UBLAS_TYPE_CHECK
356 if (! disable_type_check<bool>::value)
357 BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
358 external_logic ("external logic or bad condition of inputs"));
359#endif
360 }
361 // Sparse case
362 template<template <class T1, class T2> class F, class V, class E>
363 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
364 void vector_assign (V &v, const vector_expression<E> &e, sparse_tag) {
365 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
366 typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
367//Disabled warning C4127 because the conditional expression is constant
368#ifdef _MSC_VER
369#pragma warning(push)
370#pragma warning(disable: 4127)
371#endif
372 BOOST_STATIC_ASSERT ((!functor_type::computed));
373#ifdef _MSC_VER
374#pragma warning(pop)
375#endif
376 typedef typename V::value_type value_type;
377#if BOOST_UBLAS_TYPE_CHECK
378 vector<value_type> cv (v.size ());
379 indexing_vector_assign<scalar_assign> (cv, v);
380 indexing_vector_assign<F> (cv, e);
381#endif
382 v.clear ();
383 typename E::const_iterator ite (e ().begin ());
384 typename E::const_iterator ite_end (e ().end ());
385 while (ite != ite_end) {
386 value_type t (*ite);
387 if (t != value_type/*zero*/())
388 v.insert_element (ite.index (), t);
389 ++ ite;
390 }
391#if BOOST_UBLAS_TYPE_CHECK
392 if (! disable_type_check<bool>::value)
393 BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
394 external_logic ("external logic or bad condition of inputs"));
395#endif
396 }
397 // Sparse proxy or functional case
398 template<template <class T1, class T2> class F, class V, class E>
399 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
400 void vector_assign (V &v, const vector_expression<E> &e, sparse_proxy_tag) {
401 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
402 typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
403 typedef typename V::size_type size_type;
404 typedef typename V::difference_type difference_type;
405 typedef typename V::value_type value_type;
406
407#if BOOST_UBLAS_TYPE_CHECK
408 vector<value_type> cv (v.size ());
409 indexing_vector_assign<scalar_assign> (cv, v);
410 indexing_vector_assign<F> (cv, e);
411#endif
412 detail::make_conformant (v, e);
413
414 typename V::iterator it (v.begin ());
415 typename V::iterator it_end (v.end ());
416 typename E::const_iterator ite (e ().begin ());
417 typename E::const_iterator ite_end (e ().end ());
418 if (it != it_end && ite != ite_end) {
419 size_type it_index = it.index (), ite_index = ite.index ();
420 for (;;) {
421 difference_type compare = it_index - ite_index;
422 if (compare == 0) {
423 functor_type::apply (*it, *ite);
424 ++ it, ++ ite;
425 if (it != it_end && ite != ite_end) {
426 it_index = it.index ();
427 ite_index = ite.index ();
428 } else
429 break;
430 } else if (compare < 0) {
431//Disabled warning C4127 because the conditional expression is constant
432#ifdef _MSC_VER
433#pragma warning(push)
434#pragma warning(disable: 4127)
435#endif
436 if (!functor_type::computed) {
437#ifdef _MSC_VER
438#pragma warning(pop)
439#endif
440 functor_type::apply (*it, value_type/*zero*/());
441 ++ it;
442 } else
443 increment (it, it_end, - compare);
444 if (it != it_end)
445 it_index = it.index ();
446 else
447 break;
448 } else if (compare > 0) {
449 increment (ite, ite_end, compare);
450 if (ite != ite_end)
451 ite_index = ite.index ();
452 else
453 break;
454 }
455 }
456 }
457//Disabled warning C4127 because the conditional expression is constant
458#ifdef _MSC_VER
459#pragma warning(push)
460#pragma warning(disable: 4127)
461#endif
462 if (!functor_type::computed) {
463#ifdef _MSC_VER
464#pragma warning(pop)
465#endif
466 while (it != it_end) { // zeroing
467 functor_type::apply (*it, value_type/*zero*/());
468 ++ it;
469 }
470 } else {
471 it = it_end;
472 }
473#if BOOST_UBLAS_TYPE_CHECK
474 if (! disable_type_check<bool>::value)
475 BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
476 external_logic ("external logic or bad condition of inputs"));
477#endif
478 }
479
480 // Dispatcher
481 template<template <class T1, class T2> class F, class V, class E>
482 BOOST_UBLAS_INLINE
483 void vector_assign (V &v, const vector_expression<E> &e) {
484 typedef typename vector_assign_traits<typename V::storage_category,
485 F<typename V::reference, typename E::value_type>::computed,
486 typename E::const_iterator::iterator_category>::storage_category storage_category;
487 vector_assign<F> (v, e, storage_category ());
488 }
489
490 template<class SC, class RI>
491 struct vector_swap_traits {
492 typedef SC storage_category;
493 };
494
495 template<>
496 struct vector_swap_traits<dense_proxy_tag, sparse_bidirectional_iterator_tag> {
497 typedef sparse_proxy_tag storage_category;
498 };
499
500 template<>
501 struct vector_swap_traits<packed_proxy_tag, sparse_bidirectional_iterator_tag> {
502 typedef sparse_proxy_tag storage_category;
503 };
504
505 // Dense (proxy) case
506 template<template <class T1, class T2> class F, class V, class E>
507 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
508 void vector_swap (V &v, vector_expression<E> &e, dense_proxy_tag) {
509 typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
510 typedef typename V::difference_type difference_type;
511 difference_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
512 typename V::iterator it (v.begin ());
513 typename E::iterator ite (e ().begin ());
514 while (-- size >= 0)
515 functor_type::apply (*it, *ite), ++ it, ++ ite;
516 }
517 // Packed (proxy) case
518 template<template <class T1, class T2> class F, class V, class E>
519 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
520 void vector_swap (V &v, vector_expression<E> &e, packed_proxy_tag) {
521 typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
522 typedef typename V::difference_type difference_type;
523 typename V::iterator it (v.begin ());
524 typename V::iterator it_end (v.end ());
525 typename E::iterator ite (e ().begin ());
526 typename E::iterator ite_end (e ().end ());
527 difference_type it_size (it_end - it);
528 difference_type ite_size (ite_end - ite);
529 if (it_size > 0 && ite_size > 0) {
530 difference_type size ((std::min) (difference_type (it.index () - ite.index ()), ite_size));
531 if (size > 0) {
532 ite += size;
533 ite_size -= size;
534 }
535 }
536 if (it_size > 0 && ite_size > 0) {
537 difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
538 if (size > 0)
539 it_size -= size;
540 }
541 difference_type size ((std::min) (it_size, ite_size));
542 it_size -= size;
543 ite_size -= size;
544 while (-- size >= 0)
545 functor_type::apply (*it, *ite), ++ it, ++ ite;
546 }
547 // Sparse proxy case
548 template<template <class T1, class T2> class F, class V, class E>
549 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
550 void vector_swap (V &v, vector_expression<E> &e, sparse_proxy_tag) {
551 BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
552 typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
553 typedef typename V::size_type size_type;
554 typedef typename V::difference_type difference_type;
555
556 detail::make_conformant (v, e);
557 // FIXME should be a seperate restriction for E
558 detail::make_conformant (e (), v);
559
560 typename V::iterator it (v.begin ());
561 typename V::iterator it_end (v.end ());
562 typename E::iterator ite (e ().begin ());
563 typename E::iterator ite_end (e ().end ());
564 if (it != it_end && ite != ite_end) {
565 size_type it_index = it.index (), ite_index = ite.index ();
566 for (;;) {
567 difference_type compare = it_index - ite_index;
568 if (compare == 0) {
569 functor_type::apply (*it, *ite);
570 ++ it, ++ ite;
571 if (it != it_end && ite != ite_end) {
572 it_index = it.index ();
573 ite_index = ite.index ();
574 } else
575 break;
576 } else if (compare < 0) {
577 increment (it, it_end, - compare);
578 if (it != it_end)
579 it_index = it.index ();
580 else
581 break;
582 } else if (compare > 0) {
583 increment (ite, ite_end, compare);
584 if (ite != ite_end)
585 ite_index = ite.index ();
586 else
587 break;
588 }
589 }
590 }
591
592#if BOOST_UBLAS_TYPE_CHECK
593 increment (ite, ite_end);
594 increment (it, it_end);
595#endif
596 }
597
598 // Dispatcher
599 template<template <class T1, class T2> class F, class V, class E>
600 BOOST_UBLAS_INLINE
601 void vector_swap (V &v, vector_expression<E> &e) {
602 typedef typename vector_swap_traits<typename V::storage_category,
603 typename E::const_iterator::iterator_category>::storage_category storage_category;
604 vector_swap<F> (v, e, storage_category ());
605 }
606
607}}}
608
609#endif
610

source code of include/boost/numeric/ublas/detail/vector_assign.hpp