1 //  Copyright (c) 2000-2013
2 //  Joerg Walter, Mathias Koch. David Bellot
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See
5 //  accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 //  The authors gratefully acknowledge the support of
9 //  GeNeSys mbH & Co. KG in producing this work.
10 //
11 #ifndef _BOOST_UBLAS_EXPRESSION_TYPE_
12 #define _BOOST_UBLAS_EXPRESSION_TYPE_
13 
14 #include <boost/numeric/ublas/exception.hpp>
15 #include <boost/numeric/ublas/traits.hpp>
16 #include <boost/numeric/ublas/functional.hpp>
17 
18 
19 // Expression templates based on ideas of Todd Veldhuizen and Geoffrey Furnish
20 // Iterators based on ideas of Jeremy Siek
21 
22 namespace boost { namespace numeric { namespace ublas {
23 
24     /** \brief Base class for uBLAS statically derived expressions using the the Barton Nackman trick
25      *
26      * This is a NonAssignable class
27      * Directly implement nonassignable - simplifes debugging call trace!
28      *
29      * \tparam E an expression type
30      */
31     template<class E>
32     class ublas_expression {
33     public:
34         typedef E expression_type;
35         /* E can be an incomplete type - to define the following we would need more template arguments
36         typedef typename E::type_category type_category;
37         typedef typename E::value_type value_type;
38         */
39 
40     protected:
ublas_expression()41         ublas_expression () {}
~ublas_expression()42         ~ublas_expression () {}
43     private:
44         const ublas_expression& operator= (const ublas_expression &);
45     };
46 
47 
48     /** \brief Base class for Scalar Expression models
49      *
50      * It does not model the Scalar Expression concept but all derived types should.
51      * The class defines a common base type and some common interface for all statically
52      * derived Scalar Expression classes.
53      *
54      * We implement the casts to the statically derived type.
55      *
56      * \tparam E an expression type
57      */
58     template<class E>
59     class scalar_expression:
60         public ublas_expression<E> {
61     public:
62         typedef E expression_type;
63         typedef scalar_tag type_category;
64 
65         BOOST_UBLAS_INLINE
operator ()() const66         const expression_type &operator () () const {
67             return *static_cast<const expression_type *> (this);
68         }
69         BOOST_UBLAS_INLINE
operator ()()70         expression_type &operator () () {
71             return *static_cast<expression_type *> (this);
72         }
73     };
74 
75     template<class T>
76     class scalar_reference:
77         public scalar_expression<scalar_reference<T> > {
78 
79         typedef scalar_reference<T> self_type;
80     public:
81         typedef T value_type;
82         typedef const value_type &const_reference;
83         typedef typename boost::mpl::if_<boost::is_const<T>,
84                                           const_reference,
85                                           value_type &>::type reference;
86         typedef const self_type const_closure_type;
87         typedef const_closure_type closure_type;
88 
89         // Construction and destruction
90         BOOST_UBLAS_INLINE
scalar_reference(reference t)91         explicit scalar_reference (reference t):
92             t_ (t) {}
93 
94         // Conversion
95         BOOST_UBLAS_INLINE
operator value_type() const96         operator value_type () const {
97             return t_;
98         }
99 
100         // Assignment
101         BOOST_UBLAS_INLINE
operator =(const scalar_reference & s)102         scalar_reference &operator = (const scalar_reference &s) {
103             t_ = s.t_;
104             return *this;
105         }
106         template<class AE>
107         BOOST_UBLAS_INLINE
operator =(const scalar_expression<AE> & ae)108         scalar_reference &operator = (const scalar_expression<AE> &ae) {
109             t_ = ae;
110             return *this;
111         }
112 
113         // Closure comparison
114         BOOST_UBLAS_INLINE
same_closure(const scalar_reference & sr) const115         bool same_closure (const scalar_reference &sr) const {
116             return &t_ == &sr.t_;
117         }
118 
119     private:
120         reference t_;
121     };
122 
123     template<class T>
124     class scalar_value:
125         public scalar_expression<scalar_value<T> > {
126 
127         typedef scalar_value<T> self_type;
128     public:
129         typedef T value_type;
130         typedef const value_type &const_reference;
131         typedef typename boost::mpl::if_<boost::is_const<T>,
132                                           const_reference,
133                                           value_type &>::type reference;
134         typedef const scalar_reference<const self_type> const_closure_type;
135         typedef scalar_reference<self_type> closure_type;
136 
137         // Construction and destruction
138         BOOST_UBLAS_INLINE
scalar_value()139         scalar_value ():
140             t_ () {}
141         BOOST_UBLAS_INLINE
scalar_value(const value_type & t)142         scalar_value (const value_type &t):
143             t_ (t) {}
144 
145         BOOST_UBLAS_INLINE
operator value_type() const146         operator value_type () const {
147             return t_;
148         }
149 
150         // Assignment
151         BOOST_UBLAS_INLINE
operator =(const scalar_value & s)152         scalar_value &operator = (const scalar_value &s) {
153             t_ = s.t_;
154             return *this;
155         }
156         template<class AE>
157         BOOST_UBLAS_INLINE
operator =(const scalar_expression<AE> & ae)158         scalar_value &operator = (const scalar_expression<AE> &ae) {
159             t_ = ae;
160             return *this;
161         }
162 
163         // Closure comparison
164         BOOST_UBLAS_INLINE
same_closure(const scalar_value & sv) const165         bool same_closure (const scalar_value &sv) const {
166             return this == &sv;    // self closing on instances value
167         }
168 
169     private:
170         value_type t_;
171     };
172 
173 
174     /** \brief Base class for Vector Expression models
175      *
176      * it does not model the Vector Expression concept but all derived types should.
177      * The class defines a common base type and some common interface for all
178      * statically derived Vector Expression classes.
179      * We implement the casts to the statically derived type.
180      */
181     template<class E>
182     class vector_expression:
183         public ublas_expression<E> {
184     public:
185         static const unsigned complexity = 0;
186         typedef E expression_type;
187         typedef vector_tag type_category;
188         /* E can be an incomplete type - to define the following we would need more template arguments
189         typedef typename E::size_type size_type;
190         */
191 
192         BOOST_UBLAS_INLINE
operator ()() const193         const expression_type &operator () () const {
194             return *static_cast<const expression_type *> (this);
195         }
196         BOOST_UBLAS_INLINE
operator ()()197         expression_type &operator () () {
198             return *static_cast<expression_type *> (this);
199         }
200 
201 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
202     private:
203         // projection types
204         typedef vector_range<E> vector_range_type;
205         typedef vector_range<const E> const_vector_range_type;
206         typedef vector_slice<E> vector_slice_type;
207         typedef vector_slice<const E> const_vector_slice_type;
208         // vector_indirect_type will depend on the A template parameter
209         typedef basic_range<> default_range;    // required to avoid range/slice name confusion
210         typedef basic_slice<> default_slice;
211    public:
212         BOOST_UBLAS_INLINE
operator ()(const default_range & r) const213         const_vector_range_type operator () (const default_range &r) const {
214             return const_vector_range_type (operator () (), r);
215         }
216         BOOST_UBLAS_INLINE
operator ()(const default_range & r)217         vector_range_type operator () (const default_range &r) {
218             return vector_range_type (operator () (), r);
219         }
220         BOOST_UBLAS_INLINE
operator ()(const default_slice & s) const221         const_vector_slice_type operator () (const default_slice &s) const {
222             return const_vector_slice_type (operator () (), s);
223         }
224         BOOST_UBLAS_INLINE
operator ()(const default_slice & s)225         vector_slice_type operator () (const default_slice &s) {
226             return vector_slice_type (operator () (), s);
227         }
228         template<class A>
229         BOOST_UBLAS_INLINE
operator ()(const indirect_array<A> & ia) const230         const vector_indirect<const E, indirect_array<A> > operator () (const indirect_array<A> &ia) const {
231             return vector_indirect<const E, indirect_array<A> >  (operator () (), ia);
232         }
233         template<class A>
234         BOOST_UBLAS_INLINE
operator ()(const indirect_array<A> & ia)235         vector_indirect<E, indirect_array<A> > operator () (const indirect_array<A> &ia) {
236             return vector_indirect<E, indirect_array<A> > (operator () (), ia);
237         }
238 
239         BOOST_UBLAS_INLINE
project(const default_range & r) const240         const_vector_range_type project (const default_range &r) const {
241             return const_vector_range_type (operator () (), r);
242         }
243         BOOST_UBLAS_INLINE
project(const default_range & r)244         vector_range_type project (const default_range &r) {
245             return vector_range_type (operator () (), r);
246         }
247         BOOST_UBLAS_INLINE
project(const default_slice & s) const248         const_vector_slice_type project (const default_slice &s) const {
249             return const_vector_slice_type (operator () (), s);
250         }
251         BOOST_UBLAS_INLINE
project(const default_slice & s)252         vector_slice_type project (const default_slice &s) {
253             return vector_slice_type (operator () (), s);
254         }
255         template<class A>
256         BOOST_UBLAS_INLINE
project(const indirect_array<A> & ia) const257         const vector_indirect<const E, indirect_array<A> > project (const indirect_array<A> &ia) const {
258             return vector_indirect<const E, indirect_array<A> > (operator () (), ia);
259         }
260         template<class A>
261         BOOST_UBLAS_INLINE
project(const indirect_array<A> & ia)262         vector_indirect<E, indirect_array<A> > project (const indirect_array<A> &ia) {
263             return vector_indirect<E, indirect_array<A> > (operator () (), ia);
264         }
265 #endif
266     };
267 
268     /** \brief Base class for Vector container models
269      *
270      * it does not model the Vector concept but all derived types should.
271      * The class defines a common base type and some common interface for all
272      * statically derived Vector classes
273      * We implement the casts to the statically derived type.
274      */
275     template<class C>
276     class vector_container:
277         public vector_expression<C> {
278     public:
279         static const unsigned complexity = 0;
280         typedef C container_type;
281         typedef vector_tag type_category;
282 
283         BOOST_UBLAS_INLINE
operator ()() const284         const container_type &operator () () const {
285             return *static_cast<const container_type *> (this);
286         }
287         BOOST_UBLAS_INLINE
operator ()()288         container_type &operator () () {
289             return *static_cast<container_type *> (this);
290         }
291 
292 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
293         using vector_expression<C>::operator ();
294 #endif
295     };
296 
297 
298     /** \brief Base class for Matrix Expression models
299      *
300      * it does not model the Matrix Expression concept but all derived types should.
301      * The class defines a common base type and some common interface for all
302      * statically derived Matrix Expression classes
303      * We implement the casts to the statically derived type.
304      */
305     template<class E>
306     class matrix_expression:
307         public ublas_expression<E> {
308     private:
309         typedef matrix_expression<E> self_type;
310     public:
311         static const unsigned complexity = 0;
312         typedef E expression_type;
313         typedef matrix_tag type_category;
314         /* E can be an incomplete type - to define the following we would need more template arguments
315         typedef typename E::size_type size_type;
316         */
317 
318         BOOST_UBLAS_INLINE
operator ()() const319         const expression_type &operator () () const {
320             return *static_cast<const expression_type *> (this);
321         }
322         BOOST_UBLAS_INLINE
operator ()()323         expression_type &operator () () {
324             return *static_cast<expression_type *> (this);
325         }
326 
327 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
328     private:
329         // projection types
330         typedef vector_range<E> vector_range_type;
331         typedef const vector_range<const E> const_vector_range_type;
332         typedef vector_slice<E> vector_slice_type;
333         typedef const vector_slice<const E> const_vector_slice_type;
334         typedef matrix_row<E> matrix_row_type;
335         typedef const matrix_row<const E> const_matrix_row_type;
336         typedef matrix_column<E> matrix_column_type;
337         typedef const  matrix_column<const E> const_matrix_column_type;
338         typedef matrix_range<E> matrix_range_type;
339         typedef const matrix_range<const E> const_matrix_range_type;
340         typedef matrix_slice<E> matrix_slice_type;
341         typedef const matrix_slice<const E> const_matrix_slice_type;
342         // matrix_indirect_type will depend on the A template parameter
343         typedef basic_range<> default_range;    // required to avoid range/slice name confusion
344         typedef basic_slice<> default_slice;
345 
346     public:
347         BOOST_UBLAS_INLINE
operator [](std::size_t i) const348         const_matrix_row_type operator [] (std::size_t i) const {
349             return const_matrix_row_type (operator () (), i);
350         }
351         BOOST_UBLAS_INLINE
operator [](std::size_t i)352         matrix_row_type operator [] (std::size_t i) {
353             return matrix_row_type (operator () (), i);
354         }
355         BOOST_UBLAS_INLINE
row(std::size_t i) const356         const_matrix_row_type row (std::size_t i) const {
357             return const_matrix_row_type (operator () (), i);
358         }
359         BOOST_UBLAS_INLINE
row(std::size_t i)360         matrix_row_type row (std::size_t i) {
361             return matrix_row_type (operator () (), i);
362         }
363         BOOST_UBLAS_INLINE
column(std::size_t j) const364         const_matrix_column_type column (std::size_t j) const {
365             return const_matrix_column_type (operator () (), j);
366         }
367         BOOST_UBLAS_INLINE
column(std::size_t j)368         matrix_column_type column (std::size_t j) {
369             return matrix_column_type (operator () (), j);
370         }
371 
372         BOOST_UBLAS_INLINE
operator ()(const default_range & r1,const default_range & r2) const373         const_matrix_range_type operator () (const default_range &r1, const default_range &r2) const {
374             return const_matrix_range_type (operator () (), r1, r2);
375         }
376         BOOST_UBLAS_INLINE
operator ()(const default_range & r1,const default_range & r2)377         matrix_range_type operator () (const default_range &r1, const default_range &r2) {
378             return matrix_range_type (operator () (), r1, r2);
379         }
380         BOOST_UBLAS_INLINE
operator ()(const default_slice & s1,const default_slice & s2) const381         const_matrix_slice_type operator () (const default_slice &s1, const default_slice &s2) const {
382             return const_matrix_slice_type (operator () (), s1, s2);
383         }
384         BOOST_UBLAS_INLINE
operator ()(const default_slice & s1,const default_slice & s2)385         matrix_slice_type operator () (const default_slice &s1, const default_slice &s2) {
386             return matrix_slice_type (operator () (), s1, s2);
387         }
388         template<class A>
389         BOOST_UBLAS_INLINE
operator ()(const indirect_array<A> & ia1,const indirect_array<A> & ia2) const390         const matrix_indirect<const E, indirect_array<A> > operator () (const indirect_array<A> &ia1, const indirect_array<A> &ia2) const {
391             return matrix_indirect<const E, indirect_array<A> > (operator () (), ia1, ia2);
392         }
393         template<class A>
394         BOOST_UBLAS_INLINE
operator ()(const indirect_array<A> & ia1,const indirect_array<A> & ia2)395         matrix_indirect<E, indirect_array<A> > operator () (const indirect_array<A> &ia1, const indirect_array<A> &ia2) {
396             return matrix_indirect<E, indirect_array<A> > (operator () (), ia1, ia2);
397         }
398 
399         BOOST_UBLAS_INLINE
project(const default_range & r1,const default_range & r2) const400         const_matrix_range_type project (const default_range &r1, const default_range &r2) const {
401             return const_matrix_range_type (operator () (), r1, r2);
402         }
403         BOOST_UBLAS_INLINE
project(const default_range & r1,const default_range & r2)404         matrix_range_type project (const default_range &r1, const default_range &r2) {
405             return matrix_range_type (operator () (), r1, r2);
406         }
407         BOOST_UBLAS_INLINE
project(const default_slice & s1,const default_slice & s2) const408         const_matrix_slice_type project (const default_slice &s1, const default_slice &s2) const {
409             return const_matrix_slice_type (operator () (), s1, s2);
410         }
411         BOOST_UBLAS_INLINE
project(const default_slice & s1,const default_slice & s2)412         matrix_slice_type project (const default_slice &s1, const default_slice &s2) {
413             return matrix_slice_type (operator () (), s1, s2);
414         }
415         template<class A>
416         BOOST_UBLAS_INLINE
project(const indirect_array<A> & ia1,const indirect_array<A> & ia2) const417         const matrix_indirect<const E, indirect_array<A> > project (const indirect_array<A> &ia1, const indirect_array<A> &ia2) const {
418             return matrix_indirect<const E, indirect_array<A> > (operator () (), ia1, ia2);
419         }
420         template<class A>
421         BOOST_UBLAS_INLINE
project(const indirect_array<A> & ia1,const indirect_array<A> & ia2)422         matrix_indirect<E, indirect_array<A> > project (const indirect_array<A> &ia1, const indirect_array<A> &ia2) {
423             return matrix_indirect<E, indirect_array<A> > (operator () (), ia1, ia2);
424         }
425 #endif
426     };
427 
428 #ifdef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
429     struct iterator1_tag {};
430     struct iterator2_tag {};
431 
432     template<class I>
433     BOOST_UBLAS_INLINE
begin(const I & it,iterator1_tag)434     typename I::dual_iterator_type begin (const I &it, iterator1_tag) {
435         return it ().find2 (1, it.index1 (), 0);
436     }
437     template<class I>
438     BOOST_UBLAS_INLINE
end(const I & it,iterator1_tag)439     typename I::dual_iterator_type end (const I &it, iterator1_tag) {
440         return it ().find2 (1, it.index1 (), it ().size2 ());
441     }
442     template<class I>
443     BOOST_UBLAS_INLINE
rbegin(const I & it,iterator1_tag)444     typename I::dual_reverse_iterator_type rbegin (const I &it, iterator1_tag) {
445         return typename I::dual_reverse_iterator_type (end (it, iterator1_tag ()));
446     }
447     template<class I>
448     BOOST_UBLAS_INLINE
rend(const I & it,iterator1_tag)449     typename I::dual_reverse_iterator_type rend (const I &it, iterator1_tag) {
450         return typename I::dual_reverse_iterator_type (begin (it, iterator1_tag ()));
451     }
452 
453     template<class I>
454     BOOST_UBLAS_INLINE
begin(const I & it,iterator2_tag)455     typename I::dual_iterator_type begin (const I &it, iterator2_tag) {
456         return it ().find1 (1, 0, it.index2 ());
457     }
458     template<class I>
459     BOOST_UBLAS_INLINE
end(const I & it,iterator2_tag)460     typename I::dual_iterator_type end (const I &it, iterator2_tag) {
461         return it ().find1 (1, it ().size1 (), it.index2 ());
462     }
463     template<class I>
464     BOOST_UBLAS_INLINE
rbegin(const I & it,iterator2_tag)465     typename I::dual_reverse_iterator_type rbegin (const I &it, iterator2_tag) {
466         return typename I::dual_reverse_iterator_type (end (it, iterator2_tag ()));
467     }
468     template<class I>
469     BOOST_UBLAS_INLINE
rend(const I & it,iterator2_tag)470     typename I::dual_reverse_iterator_type rend (const I &it, iterator2_tag) {
471         return typename I::dual_reverse_iterator_type (begin (it, iterator2_tag ()));
472     }
473 #endif
474 
475     /** \brief Base class for Matrix container models
476      *
477      * it does not model the Matrix concept but all derived types should.
478      * The class defines a common base type and some common interface for all
479      * statically derived Matrix classes
480      * We implement the casts to the statically derived type.
481      */
482     template<class C>
483     class matrix_container:
484         public matrix_expression<C> {
485     public:
486         static const unsigned complexity = 0;
487         typedef C container_type;
488         typedef matrix_tag type_category;
489 
490         BOOST_UBLAS_INLINE
operator ()() const491         const container_type &operator () () const {
492             return *static_cast<const container_type *> (this);
493         }
494         BOOST_UBLAS_INLINE
operator ()()495         container_type &operator () () {
496             return *static_cast<container_type *> (this);
497         }
498 
499 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
500         using matrix_expression<C>::operator ();
501 #endif
502     };
503 
504 }}}
505 
506 #endif
507