1 //
2 //  Copyright (c) 2000-2002
3 //  Joerg Walter, Mathias Koch
4 //
5 //  Permission to use, copy, modify, distribute and sell this software
6 //  and its documentation for any purpose is hereby granted without fee,
7 //  provided that the above copyright notice appear in all copies and
8 //  that both that copyright notice and this permission notice appear
9 //  in supporting documentation.  The authors make no representations
10 //  about the suitability of this software for any purpose.
11 //  It is provided "as is" without express or implied warranty.
12 //
13 //  The authors gratefully acknowledge the support of
14 //  GeNeSys mbH & Co. KG in producing this work.
15 //
16 
17 #ifndef _BOOST_UBLAS_TRAITS_
18 #define _BOOST_UBLAS_TRAITS_
19 
20 #include <iterator>
21 #include <complex>
22 #include <cmath>
23 
24 #include <boost/numeric/ublas/detail/config.hpp>
25 #include <boost/numeric/ublas/detail/iterator.hpp>
26 #include <boost/numeric/ublas/detail/returntype_deduction.hpp>
27 
28 
29 namespace boost { namespace numeric { namespace ublas {
30 
31     // Use Joel de Guzman's return type deduction
32     // uBLAS assumes a common return type for all binary arithmetic operators
33     template<class X, class Y>
34     struct promote_traits {
35         typedef type_deduction_detail::base_result_of<X, Y> base_type;
36         static typename base_type::x_type x;
37         static typename base_type::y_type y;
38         static const std::size_t size = sizeof (
39                 type_deduction_detail::test<
40                     typename base_type::x_type
41                   , typename base_type::y_type
42                 >(x + y)     // Use x+y to stand of all the arithmetic actions
43             );
44 
45         static const std::size_t index = (size / sizeof (char)) - 1;
46         typedef typename mpl::at_c<
47             typename base_type::types, index>::type id;
48         typedef typename id::type promote_type;
49     };
50 
51 
52         // Type traits - generic numeric properties and functions
53     template<class T>
54     struct type_traits;
55 
56     // Define properties for a generic scalar type
57     template<class T>
58     struct scalar_traits {
59         typedef scalar_traits<T> self_type;
60         typedef T value_type;
61         typedef const T &const_reference;
62         typedef T &reference;
63 
64         typedef T real_type;
65         typedef real_type precision_type;       // we do not know what type has more precision then the real_type
66 
67         static const unsigned plus_complexity = 1;
68         static const unsigned multiplies_complexity = 1;
69 
70         static
71         BOOST_UBLAS_INLINE
realboost::numeric::ublas::scalar_traits72         real_type real (const_reference t) {
73                 return t;
74         }
75         static
76         BOOST_UBLAS_INLINE
imagboost::numeric::ublas::scalar_traits77         real_type imag (const_reference /*t*/) {
78                 return 0;
79         }
80         static
81         BOOST_UBLAS_INLINE
conjboost::numeric::ublas::scalar_traits82         value_type conj (const_reference t) {
83                 return t;
84         }
85 
86         static
87         BOOST_UBLAS_INLINE
absboost::numeric::ublas::scalar_traits88         real_type abs (const_reference t) {
89             return std::abs (t);
90         }
91         static
92         BOOST_UBLAS_INLINE
sqrtboost::numeric::ublas::scalar_traits93         value_type sqrt (const_reference t) {
94             return std::sqrt (t);
95         }
96 
97         static
98         BOOST_UBLAS_INLINE
norm_1boost::numeric::ublas::scalar_traits99         real_type norm_1 (const_reference t) {
100             return self_type::abs (t);
101         }
102         static
103         BOOST_UBLAS_INLINE
norm_2boost::numeric::ublas::scalar_traits104         real_type norm_2 (const_reference t) {
105             return self_type::abs (t);
106         }
107         static
108         BOOST_UBLAS_INLINE
norm_infboost::numeric::ublas::scalar_traits109         real_type norm_inf (const_reference t) {
110             return self_type::abs (t);
111         }
112 
113         static
114         BOOST_UBLAS_INLINE
equalsboost::numeric::ublas::scalar_traits115         bool equals (const_reference t1, const_reference t2) {
116             return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
117                    (std::max) ((std::max) (self_type::norm_inf (t1),
118                                        self_type::norm_inf (t2)),
119                              BOOST_UBLAS_TYPE_CHECK_MIN);
120         }
121     };
122 
123     // Define default type traits, assume T is a scalar type
124     template<class T>
125     struct type_traits : scalar_traits <T> {
126         typedef type_traits<T> self_type;
127         typedef T value_type;
128         typedef const T &const_reference;
129         typedef T &reference;
130 
131         typedef T real_type;
132         typedef real_type precision_type;
133         static const unsigned multiplies_complexity = 1;
134 
135     };
136 
137     // Define real type traits
138     template<>
139     struct type_traits<float> : scalar_traits<float> {
140         typedef type_traits<float> self_type;
141         typedef float value_type;
142         typedef const value_type &const_reference;
143         typedef value_type &reference;
144         typedef value_type real_type;
145         typedef double precision_type;
146     };
147     template<>
148     struct type_traits<double> : scalar_traits<double> {
149         typedef type_traits<double> self_type;
150         typedef double value_type;
151         typedef const value_type &const_reference;
152         typedef value_type &reference;
153         typedef value_type real_type;
154         typedef long double precision_type;
155     };
156     template<>
157     struct type_traits<long double>  : scalar_traits<long double> {
158         typedef type_traits<long double> self_type;
159         typedef long double value_type;
160         typedef const value_type &const_reference;
161         typedef value_type &reference;
162         typedef value_type real_type;
163         typedef value_type precision_type;
164     };
165 
166     // Define properties for a generic complex type
167     template<class T>
168     struct complex_traits {
169         typedef complex_traits<T> self_type;
170         typedef T value_type;
171         typedef const T &const_reference;
172         typedef T &reference;
173 
174         typedef typename T::value_type real_type;
175         typedef real_type precision_type;       // we do not know what type has more precision then the real_type
176 
177         static const unsigned plus_complexity = 2;
178         static const unsigned multiplies_complexity = 6;
179 
180         static
181         BOOST_UBLAS_INLINE
realboost::numeric::ublas::complex_traits182         real_type real (const_reference t) {
183                 return std::real (t);
184         }
185         static
186         BOOST_UBLAS_INLINE
imagboost::numeric::ublas::complex_traits187         real_type imag (const_reference t) {
188                 return std::imag (t);
189         }
190         static
191         BOOST_UBLAS_INLINE
conjboost::numeric::ublas::complex_traits192         value_type conj (const_reference t) {
193                 return std::conj (t);
194         }
195 
196         static
197         BOOST_UBLAS_INLINE
absboost::numeric::ublas::complex_traits198         real_type abs (const_reference t) {
199                 return std::abs (t);
200         }
201         static
202         BOOST_UBLAS_INLINE
sqrtboost::numeric::ublas::complex_traits203         value_type sqrt (const_reference t) {
204                 return std::sqrt (t);
205         }
206 
207         static
208         BOOST_UBLAS_INLINE
norm_1boost::numeric::ublas::complex_traits209         real_type norm_1 (const_reference t) {
210             return type_traits<real_type>::abs (self_type::real (t)) +
211                    type_traits<real_type>::abs (self_type::imag (t));
212         }
213         static
214         BOOST_UBLAS_INLINE
norm_2boost::numeric::ublas::complex_traits215         real_type norm_2 (const_reference t) {
216             return self_type::abs (t);
217         }
218         static
219         BOOST_UBLAS_INLINE
norm_infboost::numeric::ublas::complex_traits220         real_type norm_inf (const_reference t) {
221             return (std::max) (type_traits<real_type>::abs (self_type::real (t)),
222                              type_traits<real_type>::abs (self_type::imag (t)));
223         }
224 
225         static
226         BOOST_UBLAS_INLINE
equalsboost::numeric::ublas::complex_traits227         bool equals (const_reference t1, const_reference t2) {
228             return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
229                    (std::max) ((std::max) (self_type::norm_inf (t1),
230                                        self_type::norm_inf (t2)),
231                              BOOST_UBLAS_TYPE_CHECK_MIN);
232         }
233     };
234 
235     // Define complex type traits
236     template<>
237     struct type_traits<std::complex<float> > : complex_traits<std::complex<float> >{
238         typedef type_traits<std::complex<float> > self_type;
239         typedef std::complex<float> value_type;
240         typedef const value_type &const_reference;
241         typedef value_type &reference;
242         typedef float real_type;
243         typedef std::complex<double> precision_type;
244 
245     };
246     template<>
247     struct type_traits<std::complex<double> > : complex_traits<std::complex<double> >{
248         typedef type_traits<std::complex<double> > self_type;
249         typedef std::complex<double> value_type;
250         typedef const value_type &const_reference;
251         typedef value_type &reference;
252         typedef double real_type;
253         typedef std::complex<long double> precision_type;
254     };
255     template<>
256     struct type_traits<std::complex<long double> > : complex_traits<std::complex<long double> > {
257         typedef type_traits<std::complex<long double> > self_type;
258         typedef std::complex<long double> value_type;
259         typedef const value_type &const_reference;
260         typedef value_type &reference;
261         typedef long double real_type;
262         typedef value_type precision_type;
263     };
264 
265 #ifdef BOOST_UBLAS_USE_INTERVAL
266     // Define properties for a generic scalar interval type
267     template<class T>
268     struct scalar_interval_type_traits : scalar_type_traits<T> {
269         typedef scalar_interval_type_traits<T> self_type;
270         typedef boost::numeric::interval<float> value_type;
271         typedef const value_type &const_reference;
272         typedef value_type &reference;
273         typedef value_type real_type;
274         typedef real_type precision_type;       // we do not know what type has more precision then the real_type
275 
276         static const unsigned plus_complexity = 1;
277         static const unsigned multiplies_complexity = 1;
278 
279         static
280         BOOST_UBLAS_INLINE
absboost::numeric::ublas::scalar_interval_type_traits281         real_type abs (const_reference t) {
282             return boost::numeric::abs (t);
283         }
284         static
285         BOOST_UBLAS_INLINE
sqrtboost::numeric::ublas::scalar_interval_type_traits286         value_type sqrt (const_reference t) {
287             return boost::numeric::sqrt (t);
288         }
289 
290         static
291         BOOST_UBLAS_INLINE
norm_1boost::numeric::ublas::scalar_interval_type_traits292         real_type norm_1 (const_reference t) {
293             return self_type::abs (t);
294         }
295         static
296         BOOST_UBLAS_INLINE
norm_2boost::numeric::ublas::scalar_interval_type_traits297         real_type norm_2 (const_reference t) {
298             return self_type::abs (t);
299         }
300         static
301         BOOST_UBLAS_INLINE
norm_infboost::numeric::ublas::scalar_interval_type_traits302         real_type norm_inf (const_reference t) {
303             return self_type::abs (t);
304         }
305 
306         static
307         BOOST_UBLAS_INLINE
equalsboost::numeric::ublas::scalar_interval_type_traits308         bool equals (const_reference t1, const_reference t2) {
309             return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
310                    (std::max) ((std::max) (self_type::norm_inf (t1),
311                                        self_type::norm_inf (t2)),
312                              BOOST_UBLAS_TYPE_CHECK_MIN);
313         }
314     };
315 
316     // Define scalar interval type traits
317     template<>
318     struct type_traits<boost::numeric::interval<float> > : scalar_interval_type_traits<boost::numeric::interval<float> > {
319         typedef type_traits<boost::numeric::interval<float> > self_type;
320         typedef boost::numeric::interval<float> value_type;
321         typedef const value_type &const_reference;
322         typedef value_type &reference;
323         typedef value_type real_type;
324         typedef boost::numeric::interval<double> precision_type;
325 
326     };
327     template<>
328     struct type_traits<boost::numeric::interval<double> > : scalar_interval_type_traits<boost::numeric::interval<double> > {
329         typedef type_traits<boost::numeric::interval<double> > self_type;
330         typedef boost::numeric::interval<double> value_type;
331         typedef const value_type &const_reference;
332         typedef value_type &reference;
333         typedef value_type real_type;
334         typedef boost::numeric::interval<long double> precision_type;
335     };
336     template<>
337     struct type_traits<boost::numeric::interval<long double> > : scalar_interval_type_traits<boost::numeric::interval<long double> > {
338         typedef type_traits<boost::numeric::interval<long double> > self_type;
339         typedef boost::numeric::interval<long double> value_type;
340         typedef const value_type &const_reference;
341         typedef value_type &reference;
342         typedef value_type real_type;
343         typedef value_type precision_type;
344     };
345 
346 #endif
347 
348 
349     // Storage tags -- hierarchical definition of storage characteristics
350 
351     struct unknown_storage_tag {};
352     struct sparse_proxy_tag: public unknown_storage_tag {};
353     struct sparse_tag: public sparse_proxy_tag {};
354     struct packed_proxy_tag: public sparse_proxy_tag {};
355     struct packed_tag: public packed_proxy_tag {};
356     struct dense_proxy_tag: public packed_proxy_tag {};
357     struct dense_tag: public dense_proxy_tag {};
358 
359     template<class S1, class S2>
360     struct storage_restrict_traits {
361         typedef S1 storage_category;
362     };
363 
364     template<>
365     struct storage_restrict_traits<sparse_tag, dense_proxy_tag> {
366         typedef sparse_proxy_tag storage_category;
367     };
368     template<>
369     struct storage_restrict_traits<sparse_tag, packed_proxy_tag> {
370         typedef sparse_proxy_tag storage_category;
371     };
372     template<>
373     struct storage_restrict_traits<sparse_tag, sparse_proxy_tag> {
374         typedef sparse_proxy_tag storage_category;
375     };
376 
377     template<>
378     struct storage_restrict_traits<packed_tag, dense_proxy_tag> {
379         typedef packed_proxy_tag storage_category;
380     };
381     template<>
382     struct storage_restrict_traits<packed_tag, packed_proxy_tag> {
383         typedef packed_proxy_tag storage_category;
384     };
385     template<>
386     struct storage_restrict_traits<packed_tag, sparse_proxy_tag> {
387         typedef sparse_proxy_tag storage_category;
388     };
389 
390     template<>
391     struct storage_restrict_traits<packed_proxy_tag, sparse_proxy_tag> {
392         typedef sparse_proxy_tag storage_category;
393     };
394 
395     template<>
396     struct storage_restrict_traits<dense_tag, dense_proxy_tag> {
397         typedef dense_proxy_tag storage_category;
398     };
399     template<>
400     struct storage_restrict_traits<dense_tag, packed_proxy_tag> {
401         typedef packed_proxy_tag storage_category;
402     };
403     template<>
404     struct storage_restrict_traits<dense_tag, sparse_proxy_tag> {
405         typedef sparse_proxy_tag storage_category;
406     };
407 
408     template<>
409     struct storage_restrict_traits<dense_proxy_tag, packed_proxy_tag> {
410         typedef packed_proxy_tag storage_category;
411     };
412     template<>
413     struct storage_restrict_traits<dense_proxy_tag, sparse_proxy_tag> {
414         typedef sparse_proxy_tag storage_category;
415     };
416 
417 
418     // Iterator tags -- hierarchical definition of storage characteristics
419 
420     struct sparse_bidirectional_iterator_tag : public std::bidirectional_iterator_tag {};
421     struct packed_random_access_iterator_tag : public std::random_access_iterator_tag {};
422     struct dense_random_access_iterator_tag : public packed_random_access_iterator_tag {};
423 
424     // Thanks to Kresimir Fresl for convincing Comeau with iterator_base_traits ;-)
425     template<class IC>
426     struct iterator_base_traits {};
427 
428     template<>
429     struct iterator_base_traits<std::forward_iterator_tag> {
430         template<class I, class T>
431         struct iterator_base {
432             typedef forward_iterator_base<std::forward_iterator_tag, I, T> type;
433         };
434     };
435 
436     template<>
437     struct iterator_base_traits<std::bidirectional_iterator_tag> {
438         template<class I, class T>
439         struct iterator_base {
440             typedef bidirectional_iterator_base<std::bidirectional_iterator_tag, I, T> type;
441         };
442     };
443     template<>
444     struct iterator_base_traits<sparse_bidirectional_iterator_tag> {
445         template<class I, class T>
446         struct iterator_base {
447             typedef bidirectional_iterator_base<sparse_bidirectional_iterator_tag, I, T> type;
448         };
449     };
450 
451     template<>
452     struct iterator_base_traits<std::random_access_iterator_tag> {
453         template<class I, class T>
454         struct iterator_base {
455             typedef random_access_iterator_base<std::random_access_iterator_tag, I, T> type;
456         };
457     };
458     template<>
459     struct iterator_base_traits<packed_random_access_iterator_tag> {
460         template<class I, class T>
461         struct iterator_base {
462             typedef random_access_iterator_base<packed_random_access_iterator_tag, I, T> type;
463         };
464     };
465     template<>
466     struct iterator_base_traits<dense_random_access_iterator_tag> {
467         template<class I, class T>
468         struct iterator_base {
469             typedef random_access_iterator_base<dense_random_access_iterator_tag, I, T> type;
470         };
471     };
472 
473     template<class I1, class I2>
474     struct iterator_restrict_traits {
475         typedef I1 iterator_category;
476     };
477 
478     template<>
479     struct iterator_restrict_traits<packed_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
480         typedef sparse_bidirectional_iterator_tag iterator_category;
481     };
482     template<>
483     struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, packed_random_access_iterator_tag> {
484         typedef sparse_bidirectional_iterator_tag iterator_category;
485     };
486 
487     template<>
488     struct iterator_restrict_traits<dense_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
489         typedef sparse_bidirectional_iterator_tag iterator_category;
490     };
491     template<>
492     struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, dense_random_access_iterator_tag> {
493         typedef sparse_bidirectional_iterator_tag iterator_category;
494     };
495 
496     template<>
497     struct iterator_restrict_traits<dense_random_access_iterator_tag, packed_random_access_iterator_tag> {
498         typedef packed_random_access_iterator_tag iterator_category;
499     };
500     template<>
501     struct iterator_restrict_traits<packed_random_access_iterator_tag, dense_random_access_iterator_tag> {
502         typedef packed_random_access_iterator_tag iterator_category;
503     };
504 
505     template<class I>
506     BOOST_UBLAS_INLINE
increment(I & it,const I & it_end,typename I::difference_type compare,packed_random_access_iterator_tag)507     void increment (I &it, const I &it_end, typename I::difference_type compare, packed_random_access_iterator_tag) {
508         it += (std::min) (compare, it_end - it);
509     }
510     template<class I>
511     BOOST_UBLAS_INLINE
increment(I & it,const I &,typename I::difference_type,sparse_bidirectional_iterator_tag)512     void increment (I &it, const I &/* it_end */, typename I::difference_type /* compare */, sparse_bidirectional_iterator_tag) {
513         ++ it;
514     }
515     template<class I>
516     BOOST_UBLAS_INLINE
increment(I & it,const I & it_end,typename I::difference_type compare)517     void increment (I &it, const I &it_end, typename I::difference_type compare) {
518         increment (it, it_end, compare, typename I::iterator_category ());
519     }
520 
521     template<class I>
522     BOOST_UBLAS_INLINE
increment(I & it,const I & it_end)523     void increment (I &it, const I &it_end) {
524 #if BOOST_UBLAS_TYPE_CHECK
525         I cit (it);
526         while (cit != it_end) {
527             BOOST_UBLAS_CHECK (*cit == typename I::value_type/*zero*/(), internal_logic ());
528             ++ cit;
529         }
530 #endif
531         it = it_end;
532     }
533 
534 }}}
535 
536 #endif
537