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_TRAITS_
14#define _BOOST_UBLAS_TRAITS_
15
16#include <iterator>
17#include <complex>
18#include <boost/config/no_tr1/cmath.hpp>
19
20#include <boost/numeric/ublas/detail/config.hpp>
21#include <boost/numeric/ublas/detail/iterator.hpp>
22#include <boost/numeric/ublas/detail/returntype_deduction.hpp>
23#ifdef BOOST_UBLAS_USE_INTERVAL
24#include <boost/numeric/interval.hpp>
25#endif
26
27#include <boost/type_traits.hpp>
28#include <complex>
29#include <boost/typeof/typeof.hpp>
30#include <boost/utility/enable_if.hpp>
31#include <boost/type_traits/is_float.hpp>
32#include <boost/type_traits/is_integral.hpp>
33#include <boost/type_traits/is_unsigned.hpp>
34#include <boost/mpl/and.hpp>
35#include <boost/mpl/if.hpp>
36#include <boost/typeof/typeof.hpp>
37
38
39// anonymous namespace to avoid ADL issues
40namespace {
41 template<class T>
42 typename boost::mpl::if_c<boost::is_integral<T>::value,
43 double,
44 T>::type
45 boost_numeric_ublas_sqrt (const T& t) {
46 using namespace std;
47 // we'll find either std::sqrt or else another version via ADL:
48 return sqrt (t);
49 }
50
51template<typename T>
52inline typename boost::disable_if<
53 boost::is_unsigned<T>, T >::type
54 boost_numeric_ublas_abs (const T &t ) {
55 using namespace std;
56 // force a type conversion back to T for char and short types
57 return static_cast<T>(abs( t ));
58 }
59
60template<typename T>
61inline typename boost::enable_if<
62 boost::is_unsigned<T>, T >::type
63 boost_numeric_ublas_abs (const T &t ) {
64 return t;
65 }
66}
67
68namespace boost { namespace numeric { namespace ublas {
69
70
71 template<typename R, typename I>
72 typename boost::enable_if<
73 mpl::and_<
74 boost::is_float<R>,
75 boost::is_integral<I>
76 >,
77 std::complex<R> >::type inline operator+ (I in1, std::complex<R> const& in2 ) {
78 return R (in1) + in2;
79 }
80
81 template<typename R, typename I>
82 typename boost::enable_if<
83 mpl::and_<
84 boost::is_float<R>,
85 boost::is_integral<I>
86 >,
87 std::complex<R> >::type inline operator+ (std::complex<R> const& in1, I in2) {
88 return in1 + R (in2);
89 }
90
91 template<typename R, typename I>
92 typename boost::enable_if<
93 mpl::and_<
94 boost::is_float<R>,
95 boost::is_integral<I>
96 >,
97 std::complex<R> >::type inline operator- (I in1, std::complex<R> const& in2) {
98 return R (in1) - in2;
99 }
100
101 template<typename R, typename I>
102 typename boost::enable_if<
103 mpl::and_<
104 boost::is_float<R>,
105 boost::is_integral<I>
106 >,
107 std::complex<R> >::type inline operator- (std::complex<R> const& in1, I in2) {
108 return in1 - R (in2);
109 }
110
111 template<typename R, typename I>
112 typename boost::enable_if<
113 mpl::and_<
114 boost::is_float<R>,
115 boost::is_integral<I>
116 >,
117 std::complex<R> >::type inline operator* (I in1, std::complex<R> const& in2) {
118 return R (in1) * in2;
119 }
120
121 template<typename R, typename I>
122 typename boost::enable_if<
123 mpl::and_<
124 boost::is_float<R>,
125 boost::is_integral<I>
126 >,
127 std::complex<R> >::type inline operator* (std::complex<R> const& in1, I in2) {
128 return in1 * R(in2);
129 }
130
131 template<typename R, typename I>
132 typename boost::enable_if<
133 mpl::and_<
134 boost::is_float<R>,
135 boost::is_integral<I>
136 >,
137 std::complex<R> >::type inline operator/ (I in1, std::complex<R> const& in2) {
138 return R(in1) / in2;
139 }
140
141 template<typename R, typename I>
142 typename boost::enable_if<
143 mpl::and_<
144 boost::is_float<R>,
145 boost::is_integral<I>
146 >,
147 std::complex<R> >::type inline operator/ (std::complex<R> const& in1, I in2) {
148 return in1 / R (in2);
149 }
150
151 // uBLAS assumes a common return type for all binary arithmetic operators
152 template<class X, class Y>
153 struct promote_traits {
154 typedef BOOST_TYPEOF_TPL(X() + Y()) promote_type;
155 };
156
157
158
159 // Type traits - generic numeric properties and functions
160 template<class T>
161 struct type_traits;
162
163 // Define properties for a generic scalar type
164 template<class T>
165 struct scalar_traits {
166 typedef scalar_traits<T> self_type;
167 typedef T value_type;
168 typedef const T &const_reference;
169 typedef T &reference;
170
171 typedef T real_type;
172 typedef real_type precision_type; // we do not know what type has more precision then the real_type
173
174 static const unsigned plus_complexity = 1;
175 static const unsigned multiplies_complexity = 1;
176
177 static
178 BOOST_UBLAS_INLINE
179 real_type real (const_reference t) {
180 return t;
181 }
182 static
183 BOOST_UBLAS_INLINE
184 real_type imag (const_reference /*t*/) {
185 return 0;
186 }
187 static
188 BOOST_UBLAS_INLINE
189 value_type conj (const_reference t) {
190 return t;
191 }
192
193 static
194 BOOST_UBLAS_INLINE
195 real_type type_abs (const_reference t) {
196 return boost_numeric_ublas_abs (t);
197 }
198 static
199 BOOST_UBLAS_INLINE
200 value_type type_sqrt (const_reference t) {
201 // force a type conversion back to value_type for intgral types
202 return value_type (boost_numeric_ublas_sqrt (t));
203 }
204
205 static
206 BOOST_UBLAS_INLINE
207 real_type norm_1 (const_reference t) {
208 return self_type::type_abs (t);
209 }
210 static
211 BOOST_UBLAS_INLINE
212 real_type norm_2 (const_reference t) {
213 return self_type::type_abs (t);
214 }
215 static
216 BOOST_UBLAS_INLINE
217 real_type norm_inf (const_reference t) {
218 return self_type::type_abs (t);
219 }
220
221 static
222 BOOST_UBLAS_INLINE
223 bool equals (const_reference t1, const_reference t2) {
224 return self_type::norm_inf (t: t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
225 (std::max) ((std::max) (self_type::norm_inf (t: t1),
226 self_type::norm_inf (t: t2)),
227 BOOST_UBLAS_TYPE_CHECK_MIN);
228 }
229 };
230
231 // Define default type traits, assume T is a scalar type
232 template<class T>
233 struct type_traits : scalar_traits <T> {
234 typedef type_traits<T> self_type;
235 typedef T value_type;
236 typedef const T &const_reference;
237 typedef T &reference;
238
239 typedef T real_type;
240 typedef real_type precision_type;
241 static const unsigned multiplies_complexity = 1;
242
243 };
244
245 // Define real type traits
246 template<>
247 struct type_traits<float> : scalar_traits<float> {
248 typedef type_traits<float> self_type;
249 typedef float value_type;
250 typedef const value_type &const_reference;
251 typedef value_type &reference;
252 typedef value_type real_type;
253 typedef double precision_type;
254 };
255 template<>
256 struct type_traits<double> : scalar_traits<double> {
257 typedef type_traits<double> self_type;
258 typedef double value_type;
259 typedef const value_type &const_reference;
260 typedef value_type &reference;
261 typedef value_type real_type;
262 typedef long double precision_type;
263 };
264 template<>
265 struct type_traits<long double> : scalar_traits<long double> {
266 typedef type_traits<long double> self_type;
267 typedef long double value_type;
268 typedef const value_type &const_reference;
269 typedef value_type &reference;
270 typedef value_type real_type;
271 typedef value_type precision_type;
272 };
273
274 // Define properties for a generic complex type
275 template<class T>
276 struct complex_traits {
277 typedef complex_traits<T> self_type;
278 typedef T value_type;
279 typedef const T &const_reference;
280 typedef T &reference;
281
282 typedef typename T::value_type real_type;
283 typedef real_type precision_type; // we do not know what type has more precision then the real_type
284
285 static const unsigned plus_complexity = 2;
286 static const unsigned multiplies_complexity = 6;
287
288 static
289 BOOST_UBLAS_INLINE
290 real_type real (const_reference t) {
291 return std::real (t);
292 }
293 static
294 BOOST_UBLAS_INLINE
295 real_type imag (const_reference t) {
296 return std::imag (t);
297 }
298 static
299 BOOST_UBLAS_INLINE
300 value_type conj (const_reference t) {
301 return std::conj (t);
302 }
303
304 static
305 BOOST_UBLAS_INLINE
306 real_type type_abs (const_reference t) {
307 return abs (t);
308 }
309 static
310 BOOST_UBLAS_INLINE
311 value_type type_sqrt (const_reference t) {
312 return sqrt (t);
313 }
314
315 static
316 BOOST_UBLAS_INLINE
317 real_type norm_1 (const_reference t) {
318 return self_type::type_abs (t);
319 // original computation has been replaced because a complex number should behave like a scalar type
320 // return type_traits<real_type>::type_abs (self_type::real (t)) +
321 // type_traits<real_type>::type_abs (self_type::imag (t));
322 }
323 static
324 BOOST_UBLAS_INLINE
325 real_type norm_2 (const_reference t) {
326 return self_type::type_abs (t);
327 }
328 static
329 BOOST_UBLAS_INLINE
330 real_type norm_inf (const_reference t) {
331 return self_type::type_abs (t);
332 // original computation has been replaced because a complex number should behave like a scalar type
333 // return (std::max) (type_traits<real_type>::type_abs (self_type::real (t)),
334 // type_traits<real_type>::type_abs (self_type::imag (t)));
335 }
336
337 static
338 BOOST_UBLAS_INLINE
339 bool equals (const_reference t1, const_reference t2) {
340 return self_type::norm_inf (t: t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
341 (std::max) ((std::max) (self_type::norm_inf (t: t1),
342 self_type::norm_inf (t: t2)),
343 BOOST_UBLAS_TYPE_CHECK_MIN);
344 }
345 };
346
347 // Define complex type traits
348 template<>
349 struct type_traits<std::complex<float> > : complex_traits<std::complex<float> >{
350 typedef type_traits<std::complex<float> > self_type;
351 typedef std::complex<float> value_type;
352 typedef const value_type &const_reference;
353 typedef value_type &reference;
354 typedef float real_type;
355 typedef std::complex<double> precision_type;
356
357 };
358 template<>
359 struct type_traits<std::complex<double> > : complex_traits<std::complex<double> >{
360 typedef type_traits<std::complex<double> > self_type;
361 typedef std::complex<double> value_type;
362 typedef const value_type &const_reference;
363 typedef value_type &reference;
364 typedef double real_type;
365 typedef std::complex<long double> precision_type;
366 };
367 template<>
368 struct type_traits<std::complex<long double> > : complex_traits<std::complex<long double> > {
369 typedef type_traits<std::complex<long double> > self_type;
370 typedef std::complex<long double> value_type;
371 typedef const value_type &const_reference;
372 typedef value_type &reference;
373 typedef long double real_type;
374 typedef value_type precision_type;
375 };
376
377#ifdef BOOST_UBLAS_USE_INTERVAL
378 // Define scalar interval type traits
379 template<>
380 struct type_traits<boost::numeric::interval<float> > : scalar_traits<boost::numeric::interval<float> > {
381 typedef type_traits<boost::numeric::interval<float> > self_type;
382 typedef boost::numeric::interval<float> value_type;
383 typedef const value_type &const_reference;
384 typedef value_type &reference;
385 typedef value_type real_type;
386 typedef boost::numeric::interval<double> precision_type;
387
388 };
389 template<>
390 struct type_traits<boost::numeric::interval<double> > : scalar_traits<boost::numeric::interval<double> > {
391 typedef type_traits<boost::numeric::interval<double> > self_type;
392 typedef boost::numeric::interval<double> value_type;
393 typedef const value_type &const_reference;
394 typedef value_type &reference;
395 typedef value_type real_type;
396 typedef boost::numeric::interval<long double> precision_type;
397 };
398 template<>
399 struct type_traits<boost::numeric::interval<long double> > : scalar_traits<boost::numeric::interval<long double> > {
400 typedef type_traits<boost::numeric::interval<long double> > self_type;
401 typedef boost::numeric::interval<long double> value_type;
402 typedef const value_type &const_reference;
403 typedef value_type &reference;
404 typedef value_type real_type;
405 typedef value_type precision_type;
406 };
407#endif
408
409
410 // Storage tags -- hierarchical definition of storage characteristics
411
412 struct unknown_storage_tag {};
413 struct sparse_proxy_tag: public unknown_storage_tag {};
414 struct sparse_tag: public sparse_proxy_tag {};
415 struct packed_proxy_tag: public sparse_proxy_tag {};
416 struct packed_tag: public packed_proxy_tag {};
417 struct dense_proxy_tag: public packed_proxy_tag {};
418 struct dense_tag: public dense_proxy_tag {};
419
420 template<class S1, class S2>
421 struct storage_restrict_traits {
422 typedef S1 storage_category;
423 };
424
425 template<>
426 struct storage_restrict_traits<sparse_tag, dense_proxy_tag> {
427 typedef sparse_proxy_tag storage_category;
428 };
429 template<>
430 struct storage_restrict_traits<sparse_tag, packed_proxy_tag> {
431 typedef sparse_proxy_tag storage_category;
432 };
433 template<>
434 struct storage_restrict_traits<sparse_tag, sparse_proxy_tag> {
435 typedef sparse_proxy_tag storage_category;
436 };
437
438 template<>
439 struct storage_restrict_traits<packed_tag, dense_proxy_tag> {
440 typedef packed_proxy_tag storage_category;
441 };
442 template<>
443 struct storage_restrict_traits<packed_tag, packed_proxy_tag> {
444 typedef packed_proxy_tag storage_category;
445 };
446 template<>
447 struct storage_restrict_traits<packed_tag, sparse_proxy_tag> {
448 typedef sparse_proxy_tag storage_category;
449 };
450
451 template<>
452 struct storage_restrict_traits<packed_proxy_tag, sparse_proxy_tag> {
453 typedef sparse_proxy_tag storage_category;
454 };
455
456 template<>
457 struct storage_restrict_traits<dense_tag, dense_proxy_tag> {
458 typedef dense_proxy_tag storage_category;
459 };
460 template<>
461 struct storage_restrict_traits<dense_tag, packed_proxy_tag> {
462 typedef packed_proxy_tag storage_category;
463 };
464 template<>
465 struct storage_restrict_traits<dense_tag, sparse_proxy_tag> {
466 typedef sparse_proxy_tag storage_category;
467 };
468
469 template<>
470 struct storage_restrict_traits<dense_proxy_tag, packed_proxy_tag> {
471 typedef packed_proxy_tag storage_category;
472 };
473 template<>
474 struct storage_restrict_traits<dense_proxy_tag, sparse_proxy_tag> {
475 typedef sparse_proxy_tag storage_category;
476 };
477
478
479 // Iterator tags -- hierarchical definition of storage characteristics
480
481 struct sparse_bidirectional_iterator_tag : public std::bidirectional_iterator_tag {};
482 struct packed_random_access_iterator_tag : public std::random_access_iterator_tag {};
483 struct dense_random_access_iterator_tag : public packed_random_access_iterator_tag {};
484
485 // Thanks to Kresimir Fresl for convincing Comeau with iterator_base_traits ;-)
486 template<class IC>
487 struct iterator_base_traits {};
488
489 template<>
490 struct iterator_base_traits<std::forward_iterator_tag> {
491 template<class I, class T>
492 struct iterator_base {
493 typedef forward_iterator_base<std::forward_iterator_tag, I, T> type;
494 };
495 };
496
497 template<>
498 struct iterator_base_traits<std::bidirectional_iterator_tag> {
499 template<class I, class T>
500 struct iterator_base {
501 typedef bidirectional_iterator_base<std::bidirectional_iterator_tag, I, T> type;
502 };
503 };
504 template<>
505 struct iterator_base_traits<sparse_bidirectional_iterator_tag> {
506 template<class I, class T>
507 struct iterator_base {
508 typedef bidirectional_iterator_base<sparse_bidirectional_iterator_tag, I, T> type;
509 };
510 };
511
512 template<>
513 struct iterator_base_traits<std::random_access_iterator_tag> {
514 template<class I, class T>
515 struct iterator_base {
516 typedef random_access_iterator_base<std::random_access_iterator_tag, I, T> type;
517 };
518 };
519 template<>
520 struct iterator_base_traits<packed_random_access_iterator_tag> {
521 template<class I, class T>
522 struct iterator_base {
523 typedef random_access_iterator_base<packed_random_access_iterator_tag, I, T> type;
524 };
525 };
526 template<>
527 struct iterator_base_traits<dense_random_access_iterator_tag> {
528 template<class I, class T>
529 struct iterator_base {
530 typedef random_access_iterator_base<dense_random_access_iterator_tag, I, T> type;
531 };
532 };
533
534 template<class I1, class I2>
535 struct iterator_restrict_traits {
536 typedef I1 iterator_category;
537 };
538
539 template<>
540 struct iterator_restrict_traits<packed_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
541 typedef sparse_bidirectional_iterator_tag iterator_category;
542 };
543 template<>
544 struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, packed_random_access_iterator_tag> {
545 typedef sparse_bidirectional_iterator_tag iterator_category;
546 };
547
548 template<>
549 struct iterator_restrict_traits<dense_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
550 typedef sparse_bidirectional_iterator_tag iterator_category;
551 };
552 template<>
553 struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, dense_random_access_iterator_tag> {
554 typedef sparse_bidirectional_iterator_tag iterator_category;
555 };
556
557 template<>
558 struct iterator_restrict_traits<dense_random_access_iterator_tag, packed_random_access_iterator_tag> {
559 typedef packed_random_access_iterator_tag iterator_category;
560 };
561 template<>
562 struct iterator_restrict_traits<packed_random_access_iterator_tag, dense_random_access_iterator_tag> {
563 typedef packed_random_access_iterator_tag iterator_category;
564 };
565
566 template<class I>
567 BOOST_UBLAS_INLINE
568 void increment (I &it, const I &it_end, typename I::difference_type compare, packed_random_access_iterator_tag) {
569 it += (std::min) (compare, it_end - it);
570 }
571 template<class I>
572 BOOST_UBLAS_INLINE
573 void increment (I &it, const I &/* it_end */, typename I::difference_type /* compare */, sparse_bidirectional_iterator_tag) {
574 ++ it;
575 }
576 template<class I>
577 BOOST_UBLAS_INLINE
578 void increment (I &it, const I &it_end, typename I::difference_type compare) {
579 increment (it, it_end, compare, typename I::iterator_category ());
580 }
581
582 template<class I>
583 BOOST_UBLAS_INLINE
584 void increment (I &it, const I &it_end) {
585#if BOOST_UBLAS_TYPE_CHECK
586 I cit (it);
587 while (cit != it_end) {
588 BOOST_UBLAS_CHECK (*cit == typename I::value_type/*zero*/(), internal_logic ());
589 ++ cit;
590 }
591#endif
592 it = it_end;
593 }
594
595 namespace detail {
596
597 // specialisation which define whether a type has a trivial constructor
598 // or not. This is used by array types.
599 template<typename T>
600 struct has_trivial_constructor : public boost::has_trivial_constructor<T> {};
601
602 template<typename T>
603 struct has_trivial_destructor : public boost::has_trivial_destructor<T> {};
604
605 template<typename FLT>
606 struct has_trivial_constructor<std::complex<FLT> > : public has_trivial_constructor<FLT> {};
607
608 template<typename FLT>
609 struct has_trivial_destructor<std::complex<FLT> > : public has_trivial_destructor<FLT> {};
610
611 }
612
613
614 /** \brief Traits class to extract type information from a constant matrix or vector CONTAINER.
615 *
616 */
617 template < class E >
618 struct container_view_traits {
619 /// type of indices
620 typedef typename E::size_type size_type;
621 /// type of differences of indices
622 typedef typename E::difference_type difference_type;
623
624 /// storage category: \c unknown_storage_tag, \c dense_tag, \c packed_tag, ...
625 typedef typename E::storage_category storage_category;
626
627 /// type of elements
628 typedef typename E::value_type value_type;
629 /// const reference to an element
630 typedef typename E::const_reference const_reference;
631
632 /// type used in expressions to mark a reference to this class (usually a const container_reference<const E> or the class itself)
633 typedef typename E::const_closure_type const_closure_type;
634 };
635
636 /** \brief Traits class to extract additional type information from a mutable matrix or vector CONTAINER.
637 *
638 */
639 template < class E >
640 struct mutable_container_traits {
641 /// reference to an element
642 typedef typename E::reference reference;
643
644 /// type used in expressions to mark a reference to this class (usually a container_reference<E> or the class itself)
645 typedef typename E::closure_type closure_type;
646 };
647
648 /** \brief Traits class to extract type information from a matrix or vector CONTAINER.
649 *
650 */
651 template < class E >
652 struct container_traits
653 : container_view_traits<E>, mutable_container_traits<E> {
654
655 };
656
657
658 /** \brief Traits class to extract type information from a constant MATRIX.
659 *
660 */
661 template < class MATRIX >
662 struct matrix_view_traits : container_view_traits <MATRIX> {
663
664 /// orientation of the matrix, either \c row_major_tag, \c column_major_tag or \c unknown_orientation_tag
665 typedef typename MATRIX::orientation_category orientation_category;
666
667 /// row iterator for the matrix
668 typedef typename MATRIX::const_iterator1 const_iterator1;
669
670 /// column iterator for the matrix
671 typedef typename MATRIX::const_iterator2 const_iterator2;
672 };
673
674 /** \brief Traits class to extract additional type information from a mutable MATRIX.
675 *
676 */
677 template < class MATRIX >
678 struct mutable_matrix_traits
679 : mutable_container_traits <MATRIX> {
680
681 /// row iterator for the matrix
682 typedef typename MATRIX::iterator1 iterator1;
683
684 /// column iterator for the matrix
685 typedef typename MATRIX::iterator2 iterator2;
686 };
687
688
689 /** \brief Traits class to extract type information from a MATRIX.
690 *
691 */
692 template < class MATRIX >
693 struct matrix_traits
694 : matrix_view_traits <MATRIX>, mutable_matrix_traits <MATRIX> {
695 };
696
697 /** \brief Traits class to extract type information from a VECTOR.
698 *
699 */
700 template < class VECTOR >
701 struct vector_view_traits : container_view_traits <VECTOR> {
702
703 /// iterator for the VECTOR
704 typedef typename VECTOR::const_iterator const_iterator;
705
706 /// iterator pointing to the first element
707 static
708 const_iterator begin(const VECTOR & v) {
709 return v.begin();
710 }
711 /// iterator pointing behind the last element
712 static
713 const_iterator end(const VECTOR & v) {
714 return v.end();
715 }
716
717 };
718
719 /** \brief Traits class to extract type information from a VECTOR.
720 *
721 */
722 template < class VECTOR >
723 struct mutable_vector_traits : mutable_container_traits <VECTOR> {
724 /// iterator for the VECTOR
725 typedef typename VECTOR::iterator iterator;
726
727 /// iterator pointing to the first element
728 static
729 iterator begin(VECTOR & v) {
730 return v.begin();
731 }
732
733 /// iterator pointing behind the last element
734 static
735 iterator end(VECTOR & v) {
736 return v.end();
737 }
738 };
739
740 /** \brief Traits class to extract type information from a VECTOR.
741 *
742 */
743 template < class VECTOR >
744 struct vector_traits
745 : vector_view_traits <VECTOR>, mutable_vector_traits <VECTOR> {
746 };
747
748
749 // Note: specializations for T[N] and T[M][N] have been moved to traits/c_array.hpp
750
751}}}
752
753#endif
754

source code of include/boost/numeric/ublas/traits.hpp