]> Dogcows Code - chaz/yoink/blob - src/moof/cml/matrix/matrix_unroller.h
bugfix: win32 packaging script temp directories
[chaz/yoink] / src / moof / cml / matrix / matrix_unroller.h
1 /* -*- C++ -*- ------------------------------------------------------------
2
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
4
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
7
8 *-----------------------------------------------------------------------*/
9 /** @file
10 * @brief
11 *
12 * @todo Need to implement unrolling for efficient col-major array access.
13 *
14 * @todo Does it make sense to unroll an assignment if either side of the
15 * assignment has a fixed size, or just when the target matrix is fixed
16 * size?
17 */
18
19 #ifndef matrix_unroller_h
20 #define matrix_unroller_h
21
22 #include <cml/et/traits.h>
23 #include <cml/et/size_checking.h>
24 #include <cml/et/scalar_ops.h>
25
26 #if !defined(CML_2D_UNROLLER) && !defined(CML_NO_2D_UNROLLER)
27 #error "The matrix unroller has not been defined."
28 #endif
29
30 #if defined(CML_2D_UNROLLER) && !defined(CML_MATRIX_UNROLL_LIMIT)
31 #error "CML_MATRIX_UNROLL_LIMIT is undefined."
32 #endif
33
34 namespace cml {
35 namespace et {
36 namespace detail {
37
38 /** Unroll a binary assignment operator on a fixed-size matrix.
39 *
40 * This uses a forward iteration to make better use of the cache.
41 *
42 * @sa cml::matrix
43 * @sa cml::et::OpAssign
44 *
45 * @bug Need to verify that OpT is actually an assignment operator.
46 * @bug The 2D unroller needs to be specified for efficient col-major
47 * access.
48 */
49 template<class OpT, typename E, class AT, typename BO, typename L, class SrcT>
50 class MatrixAssignmentUnroller
51 {
52 protected:
53
54 /* The matrix type being assigned to: */
55 typedef cml::matrix<E,AT,BO,L> matrix_type;
56
57 /* Record traits for the arguments: */
58 typedef ExprTraits<matrix_type> dest_traits;
59 typedef ExprTraits<SrcT> src_traits;
60
61 #if defined(CML_2D_UNROLLER)
62
63 /* Forward declare: */
64 template<int R, int C, int LastRow, int LastCol, bool can_unroll>
65 struct Eval;
66
67 /* XXX This needs to be specified for efficient col-major access also! */
68
69 /** Evaluate the binary operator at element R,C. */
70 template<int R, int C, int LastRow, int LastCol>
71 struct Eval<R,C,LastRow,LastCol,true> {
72 void operator()(matrix_type& dest, const SrcT& src) const {
73
74 /* Apply to current R,C: */
75 OpT().apply(dest(R,C), src_traits().get(src,R,C));
76
77 /* Evaluate at R,C+1: */
78 Eval<R,C+1,LastRow,LastCol,true>()(dest,src);
79 }
80 };
81
82 /** Evaluate the binary operator at element R,LastCol. */
83 template<int R, int LastRow, int LastCol>
84 struct Eval<R,LastCol,LastRow,LastCol,true> {
85 void operator()(matrix_type& dest, const SrcT& src) const {
86
87 /* Apply to R,LastCol: */
88 OpT().apply(dest(R,LastCol), src_traits().get(src,R,LastCol));
89
90 /* Evaluate at R+1,0; i.e. move to next row and start the
91 * col iteration from 0:
92 */
93 Eval<R+1,0,LastRow,LastCol,true>()(dest,src);
94 }
95 };
96
97 /** Evaluate the binary operator at element LastRow,C. */
98 template<int C, int LastRow, int LastCol>
99 struct Eval<LastRow,C,LastRow,LastCol,true> {
100 void operator()(matrix_type& dest, const SrcT& src) const {
101
102 /* Apply to LastRow,C: */
103 OpT().apply(dest(LastRow,C), src_traits().get(src,LastRow,C));
104
105 /* Evaluate at LastRow,C+1: */
106 Eval<LastRow,C+1,LastRow,LastCol,true>()(dest,src);
107 }
108 };
109
110 /** Evaluate the binary operator at element LastRow,LastCol. */
111 template<int LastRow, int LastCol>
112 struct Eval<LastRow,LastCol,LastRow,LastCol,true> {
113 void operator()(matrix_type& dest, const SrcT& src) const {
114
115 /* Apply to LastRow,LastCol: */
116 OpT().apply(
117 dest(LastRow,LastCol),
118 src_traits().get(src,LastRow,LastCol));
119 }
120 };
121
122
123 /** Evaluate operators on large matrices using a loop. */
124 template<int R, int C, int LastRow, int LastCol>
125 struct Eval<R,C,LastRow,LastCol,false> {
126 void operator()(matrix_type& dest, const SrcT& src) const {
127 for(size_t i = 0; i <= LastRow; ++i) {
128 for(size_t j = 0; j <= LastCol; ++j) {
129 OpT().apply(dest(i,j), src_traits().get(src,i,j));
130 }
131 }
132 }
133 };
134
135 #endif // CML_2D_UNROLLER
136
137 #if defined(CML_NO_2D_UNROLLER)
138
139 /** Evaluate the binary operator using a loop. */
140 template<int R, int C, int LastRow, int LastCol> struct Eval {
141 void operator()(matrix_type& dest, const SrcT& src) const {
142 for(size_t i = 0; i <= LastRow; ++i) {
143 for(size_t j = 0; j <= LastCol; ++j) {
144 OpT().apply(dest(i,j), src_traits().get(src,i,j));
145 }
146 }
147 }
148 };
149
150 #endif // CML_NO_2D_UNROLLER
151
152
153 public:
154
155 /** Unroll assignment for a fixed-sized matrix. */
156 void operator()(
157 cml::matrix<E,AT,BO,L>& dest, const SrcT& src, cml::fixed_size_tag)
158 {
159 typedef cml::matrix<E,AT,BO,L> matrix_type;
160 enum {
161 LastRow = matrix_type::array_rows-1,
162 LastCol = matrix_type::array_cols-1,
163 Max = (LastRow+1)*(LastCol+1)
164 };
165
166 #if defined(CML_2D_UNROLLER)
167 typedef typename MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT>
168 ::template Eval<0, 0, LastRow, LastCol,
169 (Max <= CML_MATRIX_UNROLL_LIMIT)> Unroller;
170 #endif
171
172 #if defined(CML_NO_2D_UNROLLER)
173 /* Use a loop: */
174 typedef typename MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT>
175 ::template Eval<0, 0, LastRow, LastCol> Unroller;
176 #endif
177
178 /* Use a run-time check if src is a run-time sized expression: */
179 typedef typename ExprTraits<SrcT>::size_tag src_size;
180 typedef typename select_if<
181 same_type<src_size,dynamic_size_tag>::is_true,
182 dynamic_size_tag, fixed_size_tag>::result size_tag;
183
184 /* Check the expression size (the returned size isn't needed): */
185 CheckedSize(dest,src,size_tag());
186 /* Note: for two fixed-size expressions, the if-statements and
187 * comparisons should be completely eliminated as dead code. If
188 * src is a dynamic-sized expression, the check will still happen.
189 */
190
191 Unroller()(dest,src);
192 }
193
194
195 private:
196 /* XXX Blah, a temp. hack to fix the auto-resizing stuff below. */
197 matrix_size hack_actual_size(
198 matrix_type& dest, const SrcT& /*src*/, scalar_result_tag
199 )
200 {
201 typedef ExprTraits<matrix_type> dest_traits;
202 return dest_traits().size(dest);
203 }
204
205 matrix_size hack_actual_size(
206 matrix_type& /*dest*/, const SrcT& src, matrix_result_tag
207 )
208 {
209 typedef ExprTraits<SrcT> src_traits;
210 return src_traits().size(src);
211 }
212
213 matrix_size CheckOrResize(
214 matrix_type& dest, const SrcT& src, cml::resizable_tag)
215 {
216 #if defined(CML_AUTOMATIC_MATRIX_RESIZE_ON_ASSIGNMENT)
217 /* Get the size of src. This also causes src to check its size: */
218 matrix_size N = hack_actual_size(
219 dest, src, typename src_traits::result_tag());
220
221 /* Set the destination matrix's size: */
222 dest.resize(N.first,N.second);
223 #else
224 matrix_size N = CheckedSize(dest,src,dynamic_size_tag());
225 #endif
226 return N;
227 }
228
229 matrix_size CheckOrResize(
230 matrix_type& dest, const SrcT& src, cml::not_resizable_tag)
231 {
232 return CheckedSize(dest,src,dynamic_size_tag());
233 }
234
235
236 public:
237
238
239 /** Use a loop for dynamic-sized matrix assignment.
240 *
241 * @note The target matrix must already have the correct size.
242 *
243 * @todo This needs to be specialized for efficient row-major or col-major
244 * layout access.
245 */
246 void operator()(matrix_type& dest, const SrcT& src, cml::dynamic_size_tag)
247 {
248 typedef ExprTraits<SrcT> src_traits;
249 matrix_size N = this->CheckOrResize(
250 dest,src,typename matrix_type::resizing_tag());
251 for(size_t i = 0; i < N.first; ++i) {
252 for(size_t j = 0; j < N.second; ++j) {
253 OpT().apply(dest(i,j), src_traits().get(src,i,j));
254 /* Note: we don't need get(), since dest is a matrix. */
255 }
256 }
257 }
258 };
259
260 }
261
262 /** This constructs an assignment unroller for fixed-size arrays.
263 *
264 * The operator must be an assignment op (otherwise, this doesn't make any
265 * sense). Also, automatic unrolling is only performed for fixed-size
266 * matrices; a loop is used for dynamic-sized matrices.
267 *
268 * @sa cml::matrix
269 * @sa cml::et::OpAssign
270 *
271 * @bug Need to verify that OpT is actually an assignment operator.
272 */
273 template<class OpT, class SrcT, typename E, class AT, typename BO, typename L>
274 inline void UnrollAssignment(cml::matrix<E,AT,BO,L>& dest, const SrcT& src)
275 {
276 /* Record the destination matrix type, and the expression traits: */
277 typedef cml::matrix<E,AT,BO,L> matrix_type;
278
279 /* Record the type of the unroller: */
280 typedef detail::MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT> unroller;
281
282 /* Finally, do the unroll call: */
283 unroller()(dest, src, typename matrix_type::size_tag());
284 /* XXX It may make sense to unroll if either side is a fixed size. */
285 }
286
287 } // namespace et
288 } // namespace cml
289
290 #endif
291
292 // -------------------------------------------------------------------------
293 // vim:ft=cpp
This page took 0.046317 seconds and 4 git commands to generate.