2 // Copyright (c) 2000-2002
3 // Joerg Walter, Mathias Koch
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)
9 // The authors gratefully acknowledge the support of
10 // GeNeSys mbH & Co. KG in producing this work.
12 #ifndef _BOOST_UBLAS_EXPRESSION_TYPE_
13 #define _BOOST_UBLAS_EXPRESSION_TYPE_
15 #include <boost/numeric/ublas/exception.hpp>
16 #include <boost/numeric/ublas/traits.hpp>
17 #include <boost/numeric/ublas/functional.hpp>
20 // Expression templates based on ideas of Todd Veldhuizen and Geoffrey Furnish
21 // Iterators based on ideas of Jeremy Siek
23 namespace boost
{ namespace numeric
{ namespace ublas
{
25 // Base class for uBLAS staticaly derived expressions - see the Barton Nackman trick
26 // Provides numeric properties for linear algebra
28 class ublas_expression
{
30 typedef E expression_type
;
31 /* E can be an incomplete type - to define the following we would need more template arguments
32 typedef typename E::type_category type_category;
33 typedef typename E::value_type value_type;
36 // Directly implement nonassignable - simplifes debugging call trace!
38 ublas_expression () {}
39 ~ublas_expression () {}
41 const ublas_expression
& operator= (const ublas_expression
&);
45 // Base class for Scalar Expression models -
46 // it does not model the Scalar Expression concept but all derived types should.
47 // The class defines a common base type and some common interface for all
48 // statically derived Scalar Expression classes
49 // We implement the casts to the statically derived type.
51 class scalar_expression
:
52 public ublas_expression
<E
> {
54 typedef E expression_type
;
55 typedef scalar_tag type_category
;
58 const expression_type
&operator () () const {
59 return *static_cast<const expression_type
*> (this);
62 expression_type
&operator () () {
63 return *static_cast<expression_type
*> (this);
68 class scalar_reference
:
69 public scalar_expression
<scalar_reference
<T
> > {
71 typedef scalar_reference
<T
> self_type
;
74 typedef const value_type
&const_reference
;
75 typedef typename
boost::mpl::if_
<boost::is_const
<T
>,
77 value_type
&>::type reference
;
78 typedef const self_type const_closure_type
;
79 typedef const_closure_type closure_type
;
81 // Construction and destruction
83 explicit scalar_reference (reference t
):
88 operator value_type () const {
94 scalar_reference
&operator = (const scalar_reference
&s
) {
100 scalar_reference
&operator = (const scalar_expression
<AE
> &ae
) {
105 // Closure comparison
107 bool same_closure (const scalar_reference
&sr
) const {
108 return &t_
== &sr
.t_
;
117 public scalar_expression
<scalar_value
<T
> > {
119 typedef scalar_value
<T
> self_type
;
121 typedef T value_type
;
122 typedef const value_type
&const_reference
;
123 typedef typename
boost::mpl::if_
<boost::is_const
<T
>,
125 value_type
&>::type reference
;
126 typedef const scalar_reference
<const self_type
> const_closure_type
;
127 typedef scalar_reference
<self_type
> closure_type
;
129 // Construction and destruction
134 scalar_value (const value_type
&t
):
138 operator value_type () const {
144 scalar_value
&operator = (const scalar_value
&s
) {
150 scalar_value
&operator = (const scalar_expression
<AE
> &ae
) {
155 // Closure comparison
157 bool same_closure (const scalar_value
&sv
) const {
158 return this == &sv
; // self closing on instances value
166 // Base class for Vector Expression models -
167 // it does not model the Vector Expression concept but all derived types should.
168 // The class defines a common base type and some common interface for all
169 // statically derived Vector Expression classes
170 // We implement the casts to the statically derived type.
172 class vector_expression
:
173 public ublas_expression
<E
> {
175 static const unsigned complexity
= 0;
176 typedef E expression_type
;
177 typedef vector_tag type_category
;
178 /* E can be an incomplete type - to define the following we would need more template arguments
179 typedef typename E::size_type size_type;
183 const expression_type
&operator () () const {
184 return *static_cast<const expression_type
*> (this);
187 expression_type
&operator () () {
188 return *static_cast<expression_type
*> (this);
191 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
194 typedef vector_range
<E
> vector_range_type
;
195 typedef vector_range
<const E
> const_vector_range_type
;
196 typedef vector_slice
<E
> vector_slice_type
;
197 typedef vector_slice
<const E
> const_vector_slice_type
;
198 // vector_indirect_type will depend on the A template parameter
199 typedef basic_range
<> default_range
; // required to avoid range/slice name confusion
200 typedef basic_slice
<> default_slice
;
203 const_vector_range_type
operator () (const default_range
&r
) const {
204 return const_vector_range_type (operator () (), r
);
207 vector_range_type
operator () (const default_range
&r
) {
208 return vector_range_type (operator () (), r
);
211 const_vector_slice_type
operator () (const default_slice
&s
) const {
212 return const_vector_slice_type (operator () (), s
);
215 vector_slice_type
operator () (const default_slice
&s
) {
216 return vector_slice_type (operator () (), s
);
220 const vector_indirect
<const E
, indirect_array
<A
> > operator () (const indirect_array
<A
> &ia
) const {
221 return vector_indirect
<const E
, indirect_array
<A
> > (operator () (), ia
);
225 vector_indirect
<E
, indirect_array
<A
> > operator () (const indirect_array
<A
> &ia
) {
226 return vector_indirect
<E
, indirect_array
<A
> > (operator () (), ia
);
230 const_vector_range_type
project (const default_range
&r
) const {
231 return const_vector_range_type (operator () (), r
);
234 vector_range_type
project (const default_range
&r
) {
235 return vector_range_type (operator () (), r
);
238 const_vector_slice_type
project (const default_slice
&s
) const {
239 return const_vector_slice_type (operator () (), s
);
242 vector_slice_type
project (const default_slice
&s
) {
243 return vector_slice_type (operator () (), s
);
247 const vector_indirect
<const E
, indirect_array
<A
> > project (const indirect_array
<A
> &ia
) const {
248 return vector_indirect
<const E
, indirect_array
<A
> > (operator () (), ia
);
252 vector_indirect
<E
, indirect_array
<A
> > project (const indirect_array
<A
> &ia
) {
253 return vector_indirect
<E
, indirect_array
<A
> > (operator () (), ia
);
258 // Base class for Vector container models -
259 // it does not model the Vector concept but all derived types should.
260 // The class defines a common base type and some common interface for all
261 // statically derived Vector classes
262 // We implement the casts to the statically derived type.
264 class vector_container
:
265 public vector_expression
<C
> {
267 static const unsigned complexity
= 0;
268 typedef C container_type
;
269 typedef vector_tag type_category
;
272 const container_type
&operator () () const {
273 return *static_cast<const container_type
*> (this);
276 container_type
&operator () () {
277 return *static_cast<container_type
*> (this);
280 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
281 using vector_expression
<C
>::operator ();
286 // Base class for Matrix Expression models -
287 // it does not model the Matrix Expression concept but all derived types should.
288 // The class defines a common base type and some common interface for all
289 // statically derived Matrix Expression classes
290 // We implement the casts to the statically derived type.
292 class matrix_expression
:
293 public ublas_expression
<E
> {
295 typedef matrix_expression
<E
> self_type
;
297 static const unsigned complexity
= 0;
298 typedef E expression_type
;
299 typedef matrix_tag type_category
;
300 /* E can be an incomplete type - to define the following we would need more template arguments
301 typedef typename E::size_type size_type;
305 const expression_type
&operator () () const {
306 return *static_cast<const expression_type
*> (this);
309 expression_type
&operator () () {
310 return *static_cast<expression_type
*> (this);
313 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
316 typedef vector_range
<E
> vector_range_type
;
317 typedef const vector_range
<const E
> const_vector_range_type
;
318 typedef vector_slice
<E
> vector_slice_type
;
319 typedef const vector_slice
<const E
> const_vector_slice_type
;
320 typedef matrix_row
<E
> matrix_row_type
;
321 typedef const matrix_row
<const E
> const_matrix_row_type
;
322 typedef matrix_column
<E
> matrix_column_type
;
323 typedef const matrix_column
<const E
> const_matrix_column_type
;
324 typedef matrix_range
<E
> matrix_range_type
;
325 typedef const matrix_range
<const E
> const_matrix_range_type
;
326 typedef matrix_slice
<E
> matrix_slice_type
;
327 typedef const matrix_slice
<const E
> const_matrix_slice_type
;
328 // matrix_indirect_type will depend on the A template parameter
329 typedef basic_range
<> default_range
; // required to avoid range/slice name confusion
330 typedef basic_slice
<> default_slice
;
334 const_matrix_row_type
operator [] (std::size_t i
) const {
335 return const_matrix_row_type (operator () (), i
);
338 matrix_row_type
operator [] (std::size_t i
) {
339 return matrix_row_type (operator () (), i
);
342 const_matrix_row_type
row (std::size_t i
) const {
343 return const_matrix_row_type (operator () (), i
);
346 matrix_row_type
row (std::size_t i
) {
347 return matrix_row_type (operator () (), i
);
350 const_matrix_column_type
column (std::size_t j
) const {
351 return const_matrix_column_type (operator () (), j
);
354 matrix_column_type
column (std::size_t j
) {
355 return matrix_column_type (operator () (), j
);
359 const_matrix_range_type
operator () (const default_range
&r1
, const default_range
&r2
) const {
360 return const_matrix_range_type (operator () (), r1
, r2
);
363 matrix_range_type
operator () (const default_range
&r1
, const default_range
&r2
) {
364 return matrix_range_type (operator () (), r1
, r2
);
367 const_matrix_slice_type
operator () (const default_slice
&s1
, const default_slice
&s2
) const {
368 return const_matrix_slice_type (operator () (), s1
, s2
);
371 matrix_slice_type
operator () (const default_slice
&s1
, const default_slice
&s2
) {
372 return matrix_slice_type (operator () (), s1
, s2
);
376 const matrix_indirect
<const E
, indirect_array
<A
> > operator () (const indirect_array
<A
> &ia1
, const indirect_array
<A
> &ia2
) const {
377 return matrix_indirect
<const E
, indirect_array
<A
> > (operator () (), ia1
, ia2
);
381 matrix_indirect
<E
, indirect_array
<A
> > operator () (const indirect_array
<A
> &ia1
, const indirect_array
<A
> &ia2
) {
382 return matrix_indirect
<E
, indirect_array
<A
> > (operator () (), ia1
, ia2
);
386 const_matrix_range_type
project (const default_range
&r1
, const default_range
&r2
) const {
387 return const_matrix_range_type (operator () (), r1
, r2
);
390 matrix_range_type
project (const default_range
&r1
, const default_range
&r2
) {
391 return matrix_range_type (operator () (), r1
, r2
);
394 const_matrix_slice_type
project (const default_slice
&s1
, const default_slice
&s2
) const {
395 return const_matrix_slice_type (operator () (), s1
, s2
);
398 matrix_slice_type
project (const default_slice
&s1
, const default_slice
&s2
) {
399 return matrix_slice_type (operator () (), s1
, s2
);
403 const matrix_indirect
<const E
, indirect_array
<A
> > project (const indirect_array
<A
> &ia1
, const indirect_array
<A
> &ia2
) const {
404 return matrix_indirect
<const E
, indirect_array
<A
> > (operator () (), ia1
, ia2
);
408 matrix_indirect
<E
, indirect_array
<A
> > project (const indirect_array
<A
> &ia1
, const indirect_array
<A
> &ia2
) {
409 return matrix_indirect
<E
, indirect_array
<A
> > (operator () (), ia1
, ia2
);
414 #ifdef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
415 struct iterator1_tag
{};
416 struct iterator2_tag
{};
420 typename
I::dual_iterator_type
begin (const I
&it
, iterator1_tag
) {
421 return it ().find2 (1, it
.index1 (), 0);
425 typename
I::dual_iterator_type
end (const I
&it
, iterator1_tag
) {
426 return it ().find2 (1, it
.index1 (), it ().size2 ());
430 typename
I::dual_reverse_iterator_type
rbegin (const I
&it
, iterator1_tag
) {
431 return typename
I::dual_reverse_iterator_type (end (it
, iterator1_tag ()));
435 typename
I::dual_reverse_iterator_type
rend (const I
&it
, iterator1_tag
) {
436 return typename
I::dual_reverse_iterator_type (begin (it
, iterator1_tag ()));
441 typename
I::dual_iterator_type
begin (const I
&it
, iterator2_tag
) {
442 return it ().find1 (1, 0, it
.index2 ());
446 typename
I::dual_iterator_type
end (const I
&it
, iterator2_tag
) {
447 return it ().find1 (1, it ().size1 (), it
.index2 ());
451 typename
I::dual_reverse_iterator_type
rbegin (const I
&it
, iterator2_tag
) {
452 return typename
I::dual_reverse_iterator_type (end (it
, iterator2_tag ()));
456 typename
I::dual_reverse_iterator_type
rend (const I
&it
, iterator2_tag
) {
457 return typename
I::dual_reverse_iterator_type (begin (it
, iterator2_tag ()));
461 // Base class for Matrix container models -
462 // it does not model the Matrix concept but all derived types should.
463 // The class defines a common base type and some common interface for all
464 // statically derived Matrix classes
465 // We implement the casts to the statically derived type.
467 class matrix_container
:
468 public matrix_expression
<C
> {
470 static const unsigned complexity
= 0;
471 typedef C container_type
;
472 typedef matrix_tag type_category
;
475 const container_type
&operator () () const {
476 return *static_cast<const container_type
*> (this);
479 container_type
&operator () () {
480 return *static_cast<container_type
*> (this);
483 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
484 using matrix_expression
<C
>::operator ();