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 *-----------------------------------------------------------------------*/
12 * Define matrix and vector linear expression size-checking classes.
15 #ifndef size_checking_h
16 #define size_checking_h
19 #include <cml/core/cml_meta.h>
20 #include <cml/core/cml_assert.h>
21 #include <cml/core/fwd.h>
22 #include <cml/et/traits.h>
24 #if defined(_MSC_VER) && _MSC_VER < 1400
26 #pragma warning(disable:4348)
27 // XXX This is a terrible hack for VC7.1, and should really be fixed by
28 // separating out the "impl" templates from GetCheckedSize.
31 /* This is used below to create a more meaningful compile-time error when
32 * fixed-size vector arguments don't match at compile time:
34 struct incompatible_expression_size_error
;
36 /* This is used below to create a more meaningful compile-time error when a
37 * function is not provided with a square matrix or MatrixExpr argument:
39 struct square_matrix_arg_expected_error
;
47 /* Forward declare for specialization below: */
48 template<typename LeftT
, typename RightT
, typename SizeT
>
49 struct GetCheckedSize
;
51 /* Checking for fixed-size expression: */
52 template<typename LeftT
, typename RightT
>
53 struct GetCheckedSize
<LeftT
,RightT
,fixed_size_tag
>
55 /* Record argument traits: */
56 typedef ExprTraits
<LeftT
> left_traits
;
57 typedef ExprTraits
<RightT
> right_traits
;
60 typedef typename
left_traits::result_tag left_result
;
61 typedef typename
right_traits::result_tag right_result
;
64 /* For specialization below: */
65 template<typename LR
, typename RR
, class X
= void> struct impl
;
67 /* Check for two matrices (linear operators only): */
68 template<class X
> struct impl
<matrix_result_tag
,matrix_result_tag
,X
> {
69 typedef matrix_size size_type
;
71 (size_t)LeftT::array_rows
== (size_t)RightT::array_rows
72 && (size_t)LeftT::array_cols
== (size_t)RightT::array_cols
,
73 incompatible_expression_size_error
);
75 /* Record the array size as a constant: */
77 array_rows
= LeftT::array_rows
,
78 array_cols
= LeftT::array_cols
81 /* Return the matrix size: */
82 size_type
size() const { return size_type(array_rows
,array_cols
); }
85 /* Check for a matrix and a vector: */
86 template<class X
> struct impl
<matrix_result_tag
,vector_result_tag
,X
> {
87 typedef size_t size_type
;
89 (size_t)LeftT::array_cols
== (size_t)RightT::array_size
,
90 incompatible_expression_size_error
);
92 /* Record the array size as a constant: */
93 enum { array_size
= LeftT::array_rows
};
95 /* Return the vector size: */
96 size_type
size() const { return size_type(array_size
); }
99 /* Check for a vector and a matrix: */
100 template<class X
> struct impl
<vector_result_tag
,matrix_result_tag
,X
> {
101 typedef size_t size_type
;
102 CML_STATIC_REQUIRE_M(
103 (size_t)LeftT::array_size
== (size_t)RightT::array_rows
,
104 incompatible_expression_size_error
);
106 /* Record the array size as a constant: */
107 enum { array_size
= RightT::array_cols
};
109 /* Return the vector size: */
110 size_type
size() const { return size_type(array_size
); }
113 /* Check for a matrix and a scalar: */
114 template<class X
> struct impl
<matrix_result_tag
,scalar_result_tag
,X
> {
115 typedef matrix_size size_type
;
117 /* Record the array size as a constant: */
119 array_rows
= LeftT::array_rows
,
120 array_cols
= LeftT::array_cols
123 /* Return the matrix size: */
124 size_type
size() const { return size_type(array_rows
,array_cols
); }
127 /* Check for a scalar and a matrix: */
128 template<class X
> struct impl
<scalar_result_tag
,matrix_result_tag
,X
> {
129 typedef matrix_size size_type
;
131 /* Record the array size as a constant: */
133 array_rows
= RightT::array_rows
,
134 array_cols
= RightT::array_cols
137 /* Return the matrix size: */
138 size_type
size() const { return size_type(array_rows
,array_cols
); }
142 /* Check for two vectors: */
143 template<class X
> struct impl
<vector_result_tag
,vector_result_tag
,X
> {
144 typedef size_t size_type
;
145 CML_STATIC_REQUIRE_M(
146 (size_t)LeftT::array_size
== (size_t)RightT::array_size
,
147 incompatible_expression_size_error
);
149 /* Record the array size as a constant: */
150 enum { array_size
= LeftT::array_size
};
152 /* Return the vector size: */
153 size_type
size() const { return size_type(array_size
); }
156 /* Check for a vector and a scalar: */
157 template<class X
> struct impl
<vector_result_tag
,scalar_result_tag
,X
> {
158 typedef size_t size_type
;
160 /* Record the array size as a constant: */
161 enum { array_size
= LeftT::array_size
};
163 /* Return the vector size: */
164 size_type
size() const { return size_type(array_size
); }
167 /* Check for a scalar and a vector: */
168 template<class X
> struct impl
<scalar_result_tag
,vector_result_tag
,X
> {
169 typedef size_t size_type
;
171 /* Record the array size as a constant: */
172 enum { array_size
= RightT::array_size
};
174 /* Return the vector size: */
175 size_type
size() const { return size_type(array_size
); }
179 /* Check for two quaternions: */
181 struct impl
<quaternion_result_tag
,quaternion_result_tag
,X
> {
182 typedef size_t size_type
;
184 /* Record the quaternion size as a constant: */
185 enum { array_size
= 4 };
187 /* Return the quaternion size: */
188 size_type
size() const { return size_type(array_size
); }
191 /* Check for a quaternion and a vector: */
192 template<class X
> struct impl
<quaternion_result_tag
,vector_result_tag
,X
> {
193 typedef size_t size_type
;
194 CML_STATIC_REQUIRE_M(
195 RightT::array_size
== 4,
196 incompatible_expression_size_error
);
198 /* Record the quaternion size as a constant: */
199 enum { array_size
= 4 };
201 /* Return the quaternion size: */
202 size_type
size() const { return size_type(array_size
); }
205 /* Check for a vector and a quaternion: */
206 template<class X
> struct impl
<vector_result_tag
,quaternion_result_tag
,X
> {
207 typedef size_t size_type
;
208 CML_STATIC_REQUIRE_M(
209 LeftT::array_size
== 4,
210 incompatible_expression_size_error
);
212 /* Record the quaternion size as a constant: */
213 enum { array_size
= 4 };
215 /* Return the quaternion size: */
216 size_type
size() const { return size_type(array_size
); }
219 /* Check for a quaternion and a scalar: */
220 template<class X
> struct impl
<quaternion_result_tag
,scalar_result_tag
,X
> {
221 typedef size_t size_type
;
223 /* Record the quaternion size as a constant: */
224 enum { array_size
= 4 };
226 /* Return the quaternion size: */
227 size_type
size() const { return size_type(array_size
); }
230 /* Check for a scalar and a quaternion: */
231 template<class X
> struct impl
<scalar_result_tag
,quaternion_result_tag
,X
> {
232 typedef size_t size_type
;
234 /* Record the array size as a constant: */
235 enum { array_size
= 4 };
237 /* Return the quaternion size: */
238 size_type
size() const { return size_type(array_size
); }
241 /* Record the type of the checker: */
242 typedef impl
<left_result
,right_result
> check_type
;
243 typedef typename
check_type::size_type size_type
;
245 /* The implementation: */
246 size_type
operator()(const LeftT
&, const RightT
&) const {
247 return check_type().size();
251 /* Checking for resizeable expression: */
252 template<typename LeftT
, typename RightT
>
253 struct GetCheckedSize
<LeftT
,RightT
,dynamic_size_tag
>
255 /* Type of the size checker (for calling equal_or_fail): */
256 typedef GetCheckedSize
<LeftT
,RightT
,dynamic_size_tag
> self
;
258 /* Record argument traits: */
259 typedef ExprTraits
<LeftT
> left_traits
;
260 typedef ExprTraits
<RightT
> right_traits
;
263 typedef typename
left_traits::result_tag left_result
;
264 typedef typename
right_traits::result_tag right_result
;
267 /* For specialization below: */
268 template<typename LR
, typename RR
, class X
= void> struct impl
;
270 /* Return the size if the same, or fail if different: */
271 template<typename V
> V
equal_or_fail(V left
, V right
) const {
273 throw std::invalid_argument(
274 "expressions have incompatible sizes.");
278 /* Check for two matrices (linear operators only): */
279 template<class X
> struct impl
<matrix_result_tag
,matrix_result_tag
,X
> {
280 typedef matrix_size size_type
;
282 /* Return the matrix size, or fail if incompatible: */
283 size_type
size(const LeftT
& left
, const RightT
& right
) const {
284 #if defined(CML_CHECK_MATRIX_EXPR_SIZES)
285 return self().equal_or_fail(left
.size(), right
.size());
292 /* Check for a matrix and a vector: */
293 template<class X
> struct impl
<matrix_result_tag
,vector_result_tag
,X
> {
294 typedef size_t size_type
;
296 /* Return the vector size: */
297 size_type
size(const LeftT
& left
, const RightT
& right
) const {
298 #if defined(CML_CHECK_MATVEC_EXPR_SIZES)
299 self().equal_or_fail(left
.cols(), right
.size());
305 /* Check for a vector and a matrix: */
306 template<class X
> struct impl
<vector_result_tag
,matrix_result_tag
,X
> {
307 typedef size_t size_type
;
309 /* Return the vector size: */
310 size_type
size(const LeftT
& left
, const RightT
& right
) const {
311 #if defined(CML_CHECK_MATVEC_EXPR_SIZES)
312 self().equal_or_fail(left
.size(), right
.rows());
314 return right
.cols(right
);
318 /* Check for a matrix and a scalar: */
319 template<class X
> struct impl
<matrix_result_tag
,scalar_result_tag
,X
> {
320 typedef matrix_size size_type
;
322 /* Return the matrix size: */
323 size_type
size(const LeftT
& left
, const RightT
&) const {
328 /* Check for a scalar and a matrix: */
329 template<class X
> struct impl
<scalar_result_tag
,matrix_result_tag
,X
> {
330 typedef matrix_size size_type
;
332 /* Return the matrix size: */
333 size_type
size(const LeftT
&, const RightT
& right
) const {
338 /* Check for two vectors: */
339 template<class X
> struct impl
<vector_result_tag
,vector_result_tag
,X
> {
340 typedef size_t size_type
;
342 /* Return the vector size: */
343 size_type
size(const LeftT
& left
, const RightT
& right
) const {
344 #if defined(CML_CHECK_VECTOR_EXPR_SIZES)
345 return self().equal_or_fail(left
.size(), right
.size());
352 /* Check for a vector and a scalar: */
353 template<class X
> struct impl
<vector_result_tag
,scalar_result_tag
,X
> {
354 typedef size_t size_type
;
356 /* Return the vector size: */
357 size_type
size(const LeftT
& left
, const RightT
&) const {
362 /* Check for a scalar and a vector: */
363 template<class X
> struct impl
<scalar_result_tag
,vector_result_tag
,X
> {
364 typedef size_t size_type
;
366 /* Return the vector size: */
367 size_type
size(const LeftT
&, const RightT
& right
) const {
372 /* Record the type of the checker: */
373 typedef impl
<left_result
,right_result
> check_type
;
374 typedef typename
check_type::size_type size_type
;
376 /* The implementation: */
377 size_type
operator()(const LeftT
& left
, const RightT
& right
) const {
378 return check_type().size(left
,right
);
382 /** Generator for GetCheckedSize. */
383 template<typename LeftT
, typename RightT
, typename SizeTag
>
384 inline typename
et::GetCheckedSize
<LeftT
,RightT
,SizeTag
>::size_type
385 CheckedSize(const LeftT
& left
, const RightT
& right
, SizeTag
)
387 return et::GetCheckedSize
<LeftT
,RightT
,SizeTag
>()(left
,right
);
390 /** Verify the sizes of the argument matrices for matrix multiplication.
392 * @returns a the size of the resulting matrix.
394 template<typename MatT
> inline size_t
395 CheckedSquare(const MatT
&, fixed_size_tag
)
397 CML_STATIC_REQUIRE_M(
398 ((size_t)MatT::array_rows
== (size_t)MatT::array_cols
),
399 square_matrix_arg_expected_error
);
400 return (size_t)MatT::array_rows
;
403 /** Verify the sizes of the argument matrices for matrix multiplication.
405 * @returns the size of the resulting matrix.
407 template<typename MatT
> inline size_t
408 CheckedSquare(const MatT
& m
, dynamic_size_tag
)
410 matrix_size N
= m
.size();
411 et::GetCheckedSize
<MatT
,MatT
,dynamic_size_tag
>()
412 .equal_or_fail(N
.first
, N
.second
);
419 #if defined(_MSC_VER) && _MSC_VER < 1400
425 // -------------------------------------------------------------------------