matrix_unroller.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00019 #ifndef matrix_unroller_h
00020 #define matrix_unroller_h
00021 
00022 #include <cml/et/traits.h>
00023 #include <cml/et/size_checking.h>
00024 #include <cml/et/scalar_ops.h>
00025 
00026 #if !defined(CML_2D_UNROLLER) && !defined(CML_NO_2D_UNROLLER)
00027 #error "The matrix unroller has not been defined."
00028 #endif
00029 
00030 #if defined(CML_2D_UNROLLER) && !defined(CML_MATRIX_UNROLL_LIMIT)
00031 #error "CML_MATRIX_UNROLL_LIMIT is undefined."
00032 #endif
00033 
00034 namespace cml {
00035 namespace et {
00036 namespace detail {
00037 
00049 template<class OpT, typename E, class AT, typename BO, typename L, class SrcT>
00050 class MatrixAssignmentUnroller
00051 {
00052   protected:
00053 
00054     /* The matrix type being assigned to: */
00055     typedef cml::matrix<E,AT,BO,L> matrix_type;
00056 
00057     /* Record traits for the arguments: */
00058     typedef ExprTraits<matrix_type> dest_traits;
00059     typedef ExprTraits<SrcT> src_traits;
00060 
00061 #if defined(CML_2D_UNROLLER)
00062 
00063     /* Forward declare: */
00064     template<int R, int C, int LastRow, int LastCol, bool can_unroll>
00065         struct Eval;
00066 
00067     /* XXX This needs to be specified for efficient col-major access also! */
00068 
00070     template<int R, int C, int LastRow, int LastCol>
00071         struct Eval<R,C,LastRow,LastCol,true> {
00072             void operator()(matrix_type& dest, const SrcT& src) const {
00073 
00074                 /* Apply to current R,C: */
00075                 OpT().apply(dest(R,C), src_traits().get(src,R,C));
00076 
00077                 /* Evaluate at R,C+1: */
00078                 Eval<R,C+1,LastRow,LastCol,true>()(dest,src);
00079             }
00080         };
00081 
00083     template<int R, int LastRow, int LastCol>
00084         struct Eval<R,LastCol,LastRow,LastCol,true> {
00085             void operator()(matrix_type& dest, const SrcT& src) const {
00086 
00087                 /* Apply to R,LastCol: */
00088                 OpT().apply(dest(R,LastCol), src_traits().get(src,R,LastCol));
00089 
00090                 /* Evaluate at R+1,0; i.e. move to next row and start the
00091                  * col iteration from 0:
00092                  */
00093                 Eval<R+1,0,LastRow,LastCol,true>()(dest,src);
00094             }
00095         };
00096 
00098     template<int C, int LastRow, int LastCol>
00099         struct Eval<LastRow,C,LastRow,LastCol,true> {
00100             void operator()(matrix_type& dest, const SrcT& src) const {
00101 
00102                 /* Apply to LastRow,C: */
00103                 OpT().apply(dest(LastRow,C), src_traits().get(src,LastRow,C));
00104 
00105                 /* Evaluate at LastRow,C+1: */
00106                 Eval<LastRow,C+1,LastRow,LastCol,true>()(dest,src);
00107             }
00108         };
00109 
00111     template<int LastRow, int LastCol>
00112         struct Eval<LastRow,LastCol,LastRow,LastCol,true> {
00113             void operator()(matrix_type& dest, const SrcT& src) const {
00114 
00115                 /* Apply to LastRow,LastCol: */
00116                 OpT().apply(
00117                         dest(LastRow,LastCol),
00118                         src_traits().get(src,LastRow,LastCol));
00119             }
00120         };
00121 
00122 
00124     template<int R, int C, int LastRow, int LastCol>
00125         struct Eval<R,C,LastRow,LastCol,false> {
00126             void operator()(matrix_type& dest, const SrcT& src) const {
00127                 for(size_t i = 0; i <= LastRow; ++i) {
00128                     for(size_t j = 0; j <= LastCol; ++j) {
00129                         OpT().apply(dest(i,j), src_traits().get(src,i,j));
00130                     }
00131                 }
00132             }
00133         };
00134 
00135 #endif // CML_2D_UNROLLER
00136 
00137 #if defined(CML_NO_2D_UNROLLER)
00138 
00140     template<int R, int C, int LastRow, int LastCol> struct Eval {
00141         void operator()(matrix_type& dest, const SrcT& src) const {
00142             for(size_t i = 0; i <= LastRow; ++i) {
00143                 for(size_t j = 0; j <= LastCol; ++j) {
00144                     OpT().apply(dest(i,j), src_traits().get(src,i,j));
00145                 }
00146             }
00147         }
00148     };
00149 
00150 #endif // CML_NO_2D_UNROLLER
00151 
00152 
00153   public:
00154 
00156     void operator()(
00157             cml::matrix<E,AT,BO,L>& dest, const SrcT& src, cml::fixed_size_tag)
00158     {
00159         typedef cml::matrix<E,AT,BO,L> matrix_type;
00160         enum {
00161             LastRow = matrix_type::array_rows-1,
00162             LastCol = matrix_type::array_cols-1,
00163             Max = (LastRow+1)*(LastCol+1)
00164         };
00165 
00166 #if defined(CML_2D_UNROLLER)
00167         typedef typename MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT>
00168             ::template Eval<0, 0, LastRow, LastCol,
00169             (Max <= CML_MATRIX_UNROLL_LIMIT)> Unroller;
00170 #endif
00171 
00172 #if defined(CML_NO_2D_UNROLLER)
00173         /* Use a loop: */
00174         typedef typename MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT>
00175             ::template Eval<0, 0, LastRow, LastCol> Unroller;
00176 #endif
00177 
00178         /* Use a run-time check if src is a run-time sized expression: */
00179         typedef typename ExprTraits<SrcT>::size_tag src_size;
00180         typedef typename select_if<
00181             same_type<src_size,dynamic_size_tag>::is_true,
00182             dynamic_size_tag, fixed_size_tag>::result size_tag;
00183 
00184         /* Check the expression size (the returned size isn't needed): */
00185         CheckedSize(dest,src,size_tag());
00186         /* Note: for two fixed-size expressions, the if-statements and
00187          * comparisons should be completely eliminated as dead code.  If
00188          * src is a dynamic-sized expression, the check will still happen.
00189          */
00190 
00191         Unroller()(dest,src);
00192     }
00193 
00194 
00195   private:
00196     /* XXX Blah, a temp. hack to fix the auto-resizing stuff below. */
00197     matrix_size hack_actual_size(
00198         matrix_type& dest, const SrcT& /*src*/, scalar_result_tag
00199         )
00200     {
00201         typedef ExprTraits<matrix_type> dest_traits;
00202         return dest_traits().size(dest);
00203     }
00204 
00205     matrix_size hack_actual_size(
00206         matrix_type& /*dest*/, const SrcT& src, matrix_result_tag
00207         )
00208     {
00209         typedef ExprTraits<SrcT> src_traits;
00210         return src_traits().size(src);
00211     }
00212 
00213     matrix_size CheckOrResize(
00214             matrix_type& dest, const SrcT& src, cml::resizable_tag)
00215     {
00216 #if defined(CML_AUTOMATIC_MATRIX_RESIZE_ON_ASSIGNMENT)
00217         /* Get the size of src.  This also causes src to check its size: */
00218         matrix_size N = hack_actual_size(
00219             dest, src, typename src_traits::result_tag());
00220 
00221         /* Set the destination matrix's size: */
00222         dest.resize(N.first,N.second);
00223 #else
00224         matrix_size N = CheckedSize(dest,src,dynamic_size_tag());
00225 #endif
00226         return N;
00227     }
00228 
00229     matrix_size CheckOrResize(
00230             matrix_type& dest, const SrcT& src, cml::not_resizable_tag)
00231     {
00232         return CheckedSize(dest,src,dynamic_size_tag());
00233     }
00234 
00235 
00236   public:
00237 
00238 
00246     void operator()(matrix_type& dest, const SrcT& src, cml::dynamic_size_tag)
00247     {
00248         typedef ExprTraits<SrcT> src_traits;
00249         matrix_size N = this->CheckOrResize(
00250                 dest,src,typename matrix_type::resizing_tag());
00251         for(size_t i = 0; i < N.first; ++i) {
00252             for(size_t j = 0; j < N.second; ++j) {
00253                 OpT().apply(dest(i,j), src_traits().get(src,i,j));
00254                 /* Note: we don't need get(), since dest is a matrix. */
00255             }
00256         }
00257     }
00258 };
00259 
00260 }
00261 
00273 template<class OpT, class SrcT, typename E, class AT, typename BO, typename L>
00274 inline void UnrollAssignment(cml::matrix<E,AT,BO,L>& dest, const SrcT& src)
00275 {
00276     /* Record the destination matrix type, and the expression traits: */
00277     typedef cml::matrix<E,AT,BO,L> matrix_type;
00278 
00279     /* Record the type of the unroller: */
00280     typedef detail::MatrixAssignmentUnroller<OpT,E,AT,BO,L,SrcT> unroller;
00281 
00282     /* Finally, do the unroll call: */
00283     unroller()(dest, src, typename matrix_type::size_tag());
00284     /* XXX It may make sense to unroll if either side is a fixed size. */
00285 }
00286 
00287 } // namespace et
00288 } // namespace cml
00289 
00290 #endif
00291 
00292 // -------------------------------------------------------------------------
00293 // vim:ft=cpp

Generated on Sat Jul 18 19:35:27 2009 for CML 1.0 by  doxygen 1.5.9