1 /* -*- C++ -*- ------------------------------------------------------------
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
8 *-----------------------------------------------------------------------*/
10 * @brief Matrix linear expression classes.
12 * @todo Dynamic resizing needs to be integrated more naturally into
13 * mul() and matrix transpose():
20 #include <cml/et/size_checking.h>
21 #include <cml/matrix/matrix_traits.h>
22 #include <cml/matrix/matrix_promotions.h>
24 /* XXX Don't know which it should be just yet, since RVO seems to obviate the
25 * need for a reference type. However, copy by value copies the *entire
26 * expression tree rooted at the MatrixXpr<>, so this choice is bound to affect
27 * performance for some compiler or another:
29 #define MATXPR_ARG_TYPE const et::MatrixXpr<XprT>&
30 #define MATXPR_ARG_TYPE_N(_N_) const et::MatrixXpr<XprT##_N_>&
32 //#define MATXPR_ARG_TYPE const et::MatrixXpr<XprT>
33 //#define MATXPR_ARG_TYPE_N(_N_) const et::MatrixXpr<XprT##_N_>
38 /** A placeholder for a matrix expression in the expression tree. */
44 typedef MatrixXpr
<ExprT
> expr_type
;
46 /* Copy the expression by value into higher-up expressions: */
47 typedef expr_type expr_const_reference
;
49 typedef typename
ExprT::value_type value_type
;
50 typedef matrix_result_tag result_tag
;
51 typedef typename
ExprT::size_tag size_tag
; // Just inherit size type.
53 /* Store the expression traits: */
54 typedef ExprTraits
<ExprT
> expr_traits
;
56 /* Get the reference type: */
57 typedef typename
expr_traits::const_reference expr_reference
;
59 /* Get the result type: */
60 typedef typename
expr_traits::result_type result_type
;
62 /* Get the basis type: */
63 typedef typename
result_type::basis_orient basis_orient
;
65 /* Get the temporary type: */
66 typedef typename
result_type::temporary_type temporary_type
;
68 /* For matching by assignability: */
69 typedef cml::et::not_assignable_tag assignable_tag
;
74 /** Record result size as an enum (if applicable). */
75 enum { array_rows
= ExprT::array_rows
, array_cols
= ExprT::array_cols
};
80 /** Return the expression size as a pair. */
81 matrix_size
size() const {
82 return matrix_size(this->rows(),this->cols());
85 /** Return number of rows in the expression (same as subexpression). */
87 return expr_traits().rows(m_expr
);
90 /** Return number of columns in the expression (same as subexpression). */
92 return expr_traits().cols(m_expr
);
95 /** Return reference to contained expression. */
96 expr_reference
expression() const { return m_expr
; }
98 /** Compute value at index i,j of the result matrix. */
99 value_type
operator()(size_t i
, size_t j
) const {
100 return expr_traits().get(m_expr
,i
,j
);
103 /** Return element j of basis vector i. */
104 value_type
basis_element(size_t i
, size_t j
) const {
105 return basis_element(i
,j
,basis_orient());
111 /** Construct from the subexpression to store. */
112 explicit MatrixXpr(expr_reference expr
) : m_expr(expr
) {}
114 /** Copy constructor. */
115 MatrixXpr(const expr_type
& e
) : m_expr(e
.m_expr
) {}
120 value_type
basis_element(size_t i
, size_t j
, row_basis
) const {
124 value_type
basis_element(size_t i
, size_t j
, col_basis
) const {
131 expr_reference m_expr
;
136 /* Cannot be assigned to: */
137 expr_type
& operator=(const expr_type
&);
140 /** Expression traits for MatrixXpr<>. */
141 template<class ExprT
>
142 struct ExprTraits
< MatrixXpr
<ExprT
> >
144 typedef MatrixXpr
<ExprT
> expr_type
;
145 typedef ExprT arg_type
;
147 typedef typename
expr_type::value_type value_type
;
148 typedef typename
expr_type::expr_const_reference const_reference
;
149 typedef typename
expr_type::result_tag result_tag
;
150 typedef typename
expr_type::size_tag size_tag
;
151 typedef typename
expr_type::result_type result_type
;
152 typedef typename
expr_type::assignable_tag assignable_tag
;
153 typedef expr_node_tag node_tag
;
155 value_type
get(const expr_type
& e
, size_t i
, size_t j
) const {
160 matrix_size
size(const expr_type
& e
) const { return e
.size(); }
161 size_t rows(const expr_type
& e
) const { return e
.rows(); }
162 size_t cols(const expr_type
& e
) const { return e
.cols(); }
166 /** A unary matrix expression operating on matrix elements as a list.
168 * The operator must take exactly one argument.
170 template<class ExprT
, class OpT
>
175 typedef UnaryMatrixOp
<ExprT
,OpT
> expr_type
;
177 /* Record ary-ness of the expression: */
178 typedef unary_expression expr_ary
;
180 /* Copy the expression by value into higher-up expressions: */
181 typedef expr_type expr_const_reference
;
183 typedef typename
OpT::value_type value_type
;
184 typedef matrix_result_tag result_tag
;
185 typedef typename
ExprT::size_tag size_tag
;
187 /* Store the expression traits for the subexpression: */
188 typedef ExprTraits
<ExprT
> expr_traits
;
190 /* Reference type for the subexpression: */
191 typedef typename
expr_traits::const_reference expr_reference
;
193 /* Get the result type: */
194 typedef typename
expr_traits::result_type result_type
;
196 /* Get the temporary type: */
197 typedef typename
result_type::temporary_type temporary_type
;
199 /* For matching by assignability: */
200 typedef cml::et::not_assignable_tag assignable_tag
;
205 /** Record result size as an enum (if applicable). */
206 enum { array_rows
= ExprT::array_rows
, array_cols
= ExprT::array_cols
};
211 /** Return the expression size as a pair. */
212 matrix_size
size() const {
213 return matrix_size(this->rows(),this->cols());
216 /** Return number of rows in the expression (same as argument). */
217 size_t rows() const {
218 return expr_traits().rows(m_expr
);
221 /** Return number of columns in the expression (same as argument). */
222 size_t cols() const {
223 return expr_traits().cols(m_expr
);
226 /** Compute value at index i,j of the result matrix. */
227 value_type
operator()(size_t i
, size_t j
) const {
229 /* This uses the expression traits to figure out how to access the
230 * i,j'th element of the subexpression:
232 return OpT().apply(expr_traits().get(m_expr
,i
,j
));
238 /** Construct from the subexpression. */
239 explicit UnaryMatrixOp(expr_reference expr
) : m_expr(expr
) {}
241 /** Copy constructor. */
242 UnaryMatrixOp(const expr_type
& e
) : m_expr(e
.m_expr
) {}
247 expr_reference m_expr
;
252 /* Cannot be assigned to: */
253 expr_type
& operator=(const expr_type
&);
256 /** Expression traits for UnaryMatrixOp<>. */
257 template<class ExprT
, class OpT
>
258 struct ExprTraits
< UnaryMatrixOp
<ExprT
,OpT
> >
260 typedef UnaryMatrixOp
<ExprT
,OpT
> expr_type
;
261 typedef ExprT arg_type
;
263 typedef typename
expr_type::value_type value_type
;
264 typedef typename
expr_type::expr_const_reference const_reference
;
265 typedef typename
expr_type::result_tag result_tag
;
266 typedef typename
expr_type::size_tag size_tag
;
267 typedef typename
expr_type::result_type result_type
;
268 typedef typename
expr_type::assignable_tag assignable_tag
;
269 typedef expr_node_tag node_tag
;
271 value_type
get(const expr_type
& e
, size_t i
, size_t j
) const {
275 matrix_size
size(const expr_type
& e
) const { return e
.size(); }
276 size_t rows(const expr_type
& e
) const { return e
.rows(); }
277 size_t cols(const expr_type
& e
) const { return e
.cols(); }
281 /** A binary matrix expression. */
282 template<class LeftT
, class RightT
, class OpT
>
287 typedef BinaryMatrixOp
<LeftT
,RightT
,OpT
> expr_type
;
289 /* Copy the UnaryMatrixOp expression by value into parent
290 * expression tree nodes:
292 typedef expr_type expr_const_reference
;
294 typedef typename
OpT::value_type value_type
;
295 typedef matrix_result_tag result_tag
;
297 /* For matching by assignability: */
298 typedef cml::et::not_assignable_tag assignable_tag
;
300 /* Record the expression traits for the two subexpressions: */
301 typedef ExprTraits
<LeftT
> left_traits
;
302 typedef ExprTraits
<RightT
> right_traits
;
304 /* Reference types for the two subexpressions: */
305 typedef typename
left_traits::const_reference left_reference
;
306 typedef typename
right_traits::const_reference right_reference
;
308 /* Figure out the expression's resulting (matrix) type: */
309 typedef typename
left_traits::result_type left_result
;
310 typedef typename
right_traits::result_type right_result
;
311 typedef typename MatrixPromote
<left_result
,right_result
>::type result_type
;
312 typedef typename
result_type::size_tag size_tag
;
314 /* Get the temporary type: */
315 typedef typename
result_type::temporary_type temporary_type
;
317 /* Define a size checker: */
318 typedef GetCheckedSize
<LeftT
,RightT
,size_tag
> checked_size
;
323 /** Record result size as an enum (if applicable).
325 * CheckExprSizes<> ensures that this works as expected.
328 array_rows
= result_type::array_rows
,
329 array_cols
= result_type::array_cols
335 /** Return the expression size as a pair. */
336 matrix_size
size() const {
337 return CheckedSize(m_left
,m_right
,size_tag());
340 /** Return number of rows in the result.
342 * @note Because this calls size() internally, calling both rows()
343 * and cols() with CML_CHECK_MATRIX_EXPR_SIZES defined will cause the size
344 * checking code to be executed twice.
346 size_t rows() const {
347 #if defined(CML_CHECK_MATRIX_EXPR_SIZES)
348 return this->size().first
;
350 return left_traits().rows(m_left
);
354 /** Return number of cols in the result.
356 * @note Because this calls size() internally, calling both rows()
357 * and cols() with CML_CHECK_MATRIX_EXPR_SIZES defined will cause the size
358 * checking code to be executed twice.
360 size_t cols() const {
361 #if defined(CML_CHECK_MATRIX_EXPR_SIZES)
362 return this->size().second
;
364 return right_traits().cols(m_right
);
368 /** Compute value at index i,j of the result matrix. */
369 value_type
operator()(size_t i
, size_t j
) const {
371 /* This uses the expression traits to figure out how to access the
372 * i'th index of the two subexpressions:
375 left_traits().get(m_left
,i
,j
),
376 right_traits().get(m_right
,i
,j
));
382 /** Construct from the two subexpressions.
384 * @throws std::invalid_argument if the subexpression sizes don't
387 explicit BinaryMatrixOp(left_reference left
, right_reference right
)
388 : m_left(left
), m_right(right
) {}
390 /** Copy constructor. */
391 BinaryMatrixOp(const expr_type
& e
)
392 : m_left(e
.m_left
), m_right(e
.m_right
) {}
397 left_reference m_left
;
398 right_reference m_right
;
403 /* This ensures that a compile-time size check is executed: */
404 typename
checked_size::check_type _dummy
;
409 /* Cannot be assigned to: */
410 expr_type
& operator=(const expr_type
&);
413 /** Expression traits for BinaryMatrixOp<>. */
414 template<class LeftT
, class RightT
, class OpT
>
415 struct ExprTraits
< BinaryMatrixOp
<LeftT
,RightT
,OpT
> >
417 typedef BinaryMatrixOp
<LeftT
,RightT
,OpT
> expr_type
;
418 typedef LeftT left_type
;
419 typedef RightT right_type
;
421 typedef typename
expr_type::value_type value_type
;
422 typedef typename
expr_type::expr_const_reference const_reference
;
423 typedef typename
expr_type::result_tag result_tag
;
424 typedef typename
expr_type::size_tag size_tag
;
425 typedef typename
expr_type::result_type result_type
;
426 typedef typename
expr_type::assignable_tag assignable_tag
;
427 typedef expr_node_tag node_tag
;
429 value_type
get(const expr_type
& e
, size_t i
, size_t j
) const {
433 matrix_size
size(const expr_type
& e
) const { return e
.size(); }
434 size_t rows(const expr_type
& e
) const { return e
.rows(); }
435 size_t cols(const expr_type
& e
) const { return e
.cols(); }
438 /* Helper struct to verify that both arguments are matrix expressions: */
439 template<typename LeftTraits
, typename RightTraits
>
440 struct MatrixExpressions
442 /* Require that both arguments are matrix expressions: */
443 typedef typename
LeftTraits::result_tag left_result
;
444 typedef typename
RightTraits::result_tag right_result
;
445 enum { is_true
= (same_type
<left_result
,et::matrix_result_tag
>::is_true
446 && same_type
<right_result
,et::matrix_result_tag
>::is_true
) };
451 /* XXX These are temporary helpers until dynamic resizing is integrated more
452 * naturally into mul() and matrix transpose():
454 template<typename MatT
, typename MT
> inline
455 void Resize(MatT
&, size_t, size_t, fixed_size_tag
, MT
) {}
457 template<typename MatT
> inline
459 size_t R
, size_t C
, dynamic_size_tag
, dynamic_memory_tag
)
464 template<typename MatT
> inline
465 void Resize(MatT
& m
, size_t R
, size_t C
) {
466 Resize(m
, R
, C
, typename
MatT::size_tag(), typename
MatT::memory_tag());
469 template<typename MatT
> inline
470 void Resize(MatT
& m
, matrix_size N
) {
471 Resize(m
, N
.first
, N
.second
,
472 typename
MatT::size_tag(), typename
MatT::memory_tag());
475 } // namespace detail
482 // -------------------------------------------------------------------------