Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

fmatCore.h

Go to the documentation of this file.
00001 #ifndef INCLUDED_fmatCore_h_
00002 #define INCLUDED_fmatCore_h_
00003 
00004 #include <cmath>
00005 #include <cstring>
00006 #include <iostream>
00007 #include <sstream>
00008 #include <iomanip>
00009 #include <stdexcept>
00010 #include <limits>
00011 #include "attributes.h"
00012 #include <stdio.h>
00013 #ifdef __APPLE__
00014 #  include <AvailabilityMacros.h>
00015 #endif
00016 
00017 //! fixed-size matrix routines for high performance with small allocations
00018 namespace fmat {
00019   
00020 #ifdef FMAT_DEFAULT_DOUBLE
00021   typedef double fmatReal;
00022 #else
00023   typedef float fmatReal;
00024 #endif
00025   
00026   struct Length_mismatch_or_non_vector {};
00027   struct NonSquare_Matrix {};
00028   struct SubVector_is_longer_than_source {};
00029   struct SubMatrix_has_more_rows_than_source {};
00030   struct SubMatrix_has_more_columns_than_source {};
00031   struct Rotation_requires_larger_dimensions {};
00032   struct Matrix_multiplication_left_width_must_match_right_height {};
00033   
00034   template<size_t N, typename R> class SubVector;
00035   template<size_t H, size_t W, typename T> class SubMatrix;
00036   template<size_t H, size_t W, typename T> class Matrix;
00037   template<size_t N, typename R> class Column;
00038   template<size_t N, typename R> class Row;
00039   template<typename R> inline Column<2,R> packT(R x, R y);
00040   template<typename R> inline Column<3,R> packT(R x, R y, R z);
00041   template<typename R> inline Column<4,R> packT(R x, R y, R z, R d);
00042   inline Column<2,fmatReal> pack(fmatReal x, fmatReal y);
00043   inline Column<3,fmatReal> pack(fmatReal x, fmatReal y, fmatReal z);
00044   inline Column<4,fmatReal> pack(fmatReal x, fmatReal y, fmatReal z, fmatReal d);
00045   
00046   extern std::string defaultNumberFormat;
00047   
00048   template<typename R>
00049   std::string fullfmt(const R* const data, size_t H, size_t W,
00050     std::string const &numberFormat,
00051     std::string const &firstLineStart, std::string const &nextLineStart, std::string const &lastLineEnd,
00052     std::string const &rowBegin, std::string const &elementSep, std::string const &rowEnd,
00053     std::string const &rowSep)
00054   {
00055     std::ostringstream os;
00056     char buf[100];
00057     os << firstLineStart;
00058     for (size_t r=0; r<H; r++) {
00059       if ( r > 0 )
00060         os << nextLineStart;
00061       os << rowBegin;
00062       for (size_t c=0; c<W; c++) {
00063         snprintf(buf, 100, numberFormat.c_str(), data[c*H+r]);
00064         os << buf;
00065         if ( c < (W-1) )
00066           os << elementSep;
00067       }
00068       os << rowEnd;;
00069       if ( r < (H-1) )
00070         os << rowSep;
00071     }
00072     os << lastLineEnd;
00073     return os.str();
00074   }
00075   
00076   namespace fmat_internal {
00077     template<typename T> inline void tmemcpy(T* dst, const T* src, size_t n) { memcpy(dst,src,n*sizeof(T)); }
00078     
00079 #if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_5)
00080     // memset_patternX() is only available on OS X 10.5 (and later?)
00081     template<typename T, size_t W> struct tmemset_pattern {};
00082     template<typename T> struct tmemset_pattern<T,1> { inline tmemset_pattern(T* dst, const T& src, size_t n) { memset(dst,src,n*sizeof(T)); } };
00083     template<typename T> struct tmemset_pattern<T,4> { inline tmemset_pattern(T* dst, const T& src, size_t n) { memset_pattern4(dst,&src,n*sizeof(T)); } };
00084     template<typename T> struct tmemset_pattern<T,8> { inline tmemset_pattern(T* dst, const T& src, size_t n) { memset_pattern8(dst,&src,n*sizeof(T)); } };
00085     template<typename T> struct tmemset_pattern<T,16> { inline tmemset_pattern(T* dst, const T& src, size_t n) { memset_pattern16(dst,&src,n*sizeof(T)); } };
00086 #else
00087     template<typename T, size_t W> struct tmemset_pattern {
00088       inline tmemset_pattern(T* dst, const T& src, size_t n) { while(n!=0) dst[--n]=src; }
00089     };
00090     template<typename T> struct tmemset_pattern<T,1> { inline tmemset_pattern(T* dst, const T& src, size_t n) { memset(dst,src,n*sizeof(T)); } };
00091 #endif
00092     
00093     template<typename T> void tmemset(T* dst, const T& src, size_t n) { tmemset_pattern<T,sizeof(T)>(dst,src,n); }
00094 
00095     template<class MSG,bool X> class CompileTimeAssert;
00096     template<class MSG> class CompileTimeAssert<MSG,true> {};
00097     
00098     struct NoInit { };
00099     
00100     template<typename T> struct precision_trait { };
00101     template<> struct precision_trait<bool> { static const int PRECISION_RANK = 0; };
00102     template<> struct precision_trait<char> { static const int PRECISION_RANK = 100; };
00103     template<> struct precision_trait<unsigned char> { static const int PRECISION_RANK = 200; };
00104     template<> struct precision_trait<short> { static const int PRECISION_RANK = 300; };
00105     template<> struct precision_trait<unsigned short> { static const int PRECISION_RANK = 400; };
00106     template<> struct precision_trait<int> { static const int PRECISION_RANK = 500; };
00107     template<> struct precision_trait<unsigned int> { static const int PRECISION_RANK = 600; };
00108     template<> struct precision_trait<long> { static const int PRECISION_RANK = 700; };
00109     template<> struct precision_trait<unsigned long> { static const int PRECISION_RANK = 800; };
00110     template<> struct precision_trait<float> { static const int PRECISION_RANK = 900; };
00111     template<> struct precision_trait<double> { static const int PRECISION_RANK = 1000; };
00112     template<> struct precision_trait<long double> { static const int PRECISION_RANK = 1100; };
00113     
00114     template<typename T> struct unconst { typedef T type; };
00115     template<> struct unconst<const bool> { typedef bool type; };
00116     template<> struct unconst<const char> { typedef char type; };
00117     template<> struct unconst<const unsigned char> { typedef unsigned char type; };
00118     template<> struct unconst<const short> { typedef short type; };
00119     template<> struct unconst<const unsigned short> { typedef unsigned short type; };
00120     template<> struct unconst<const int> { typedef int type; };
00121     template<> struct unconst<const unsigned int> { typedef unsigned int type; };
00122     template<> struct unconst<const long> { typedef long type; };
00123     template<> struct unconst<const unsigned long> { typedef unsigned long type; };
00124     template<> struct unconst<const float> { typedef float type; };
00125     template<> struct unconst<const double> { typedef double type; };
00126     template<> struct unconst<const long double> { typedef long double type; };
00127     
00128     template<typename T1, typename T2, bool promoteT1>
00129     struct do_promotion { typedef T1 type; };
00130     template<typename T1, typename T2>
00131     struct do_promotion<T1,T2,false> { typedef T2 type; };
00132     
00133     template<typename T1, typename T2>
00134     struct promotion_trait {
00135       typedef typename unconst<T1>::type mT1;
00136       typedef typename unconst<T2>::type mT2;
00137       static const bool USET1 = (precision_trait<mT1>::PRECISION_RANK) > (precision_trait<mT2>::PRECISION_RANK);
00138       typedef typename do_promotion<mT1,mT2,USET1>::type type;
00139     };
00140 
00141     template<class T1, class T2>
00142     struct mmops {
00143       typedef typename T1::storage_t R1;
00144       typedef typename T2::storage_t R2;
00145       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
00146       static Matrix<T1::HEIGHT,T2::WIDTH,R> multiply(const T1& a, const T2& b) {
00147         Matrix<T1::HEIGHT,T2::WIDTH,R> ans=fmat_internal::NoInit();
00148         for(size_t c2=T2::WIDTH; c2--!=0;) {
00149           for(size_t r1=T1::HEIGHT; r1--!=0;) {
00150             R x=0;
00151             for(size_t r2=T1::WIDTH; r2--!=0;)
00152               x+=a(r1,r2)*b(r2,c2);
00153             ans(r1,c2)=x;
00154           }
00155         }
00156         return ans;
00157       }
00158     };
00159   
00160     template<class M, class V>
00161     struct mvops {
00162       typedef typename M::storage_t MR;
00163       typedef typename V::storage_t VR;
00164       typedef typename fmat_internal::promotion_trait<MR,VR>::type R;
00165       enum {
00166         H=M::HEIGHT,
00167         N=V::CAP,
00168         W=M::WIDTH
00169       };
00170       static Column<H,R> multiply(const M& a, const V& b) {
00171         (void)sizeof(fmat_internal::CompileTimeAssert<Matrix_multiplication_left_width_must_match_right_height,M::WIDTH==V::HEIGHT>);
00172         Column<H,R> ans=fmat_internal::NoInit();
00173         for(size_t r=H; r--!=0;) {
00174           R x=0;
00175           for(size_t c=N; c--!=0;)
00176             x+=a(r,c)*b[c];
00177           ans[r]=x;
00178         }
00179         return ans;
00180       }
00181       static Row<W,R> multiply(const V& a, const M& b) {
00182         (void)sizeof(fmat_internal::CompileTimeAssert<Matrix_multiplication_left_width_must_match_right_height,V::WIDTH==M::HEIGHT>);
00183         Row<W,R> ans=fmat_internal::NoInit();
00184         for(size_t c=W; c--!=0;) {
00185           R x=0;
00186           for(size_t r=N; r--!=0;)
00187             x+=b[r]*a(r,c);
00188           ans[c]=x;
00189         }
00190         return ans;
00191       }
00192     };
00193   }
00194   
00195   template<size_t N, typename R=fmatReal>
00196   class SubVector {
00197     template<size_t S, typename T> friend class SubVector;
00198     template<size_t S, typename T> friend class Column;
00199     template<size_t S, typename T> friend class Row;
00200     template<size_t H, size_t W, typename T> friend class SubMatrix;
00201     template<size_t H, size_t W, typename T> friend class Matrix;
00202   public:
00203     // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00204 #if defined(__clang__) || !defined(__GNUC__) || (__GNUC__==4 && __GNUC_MINOR__<1)
00205     static const size_t HEIGHT=N;
00206     static const size_t WIDTH=1;
00207     static const size_t CAP=N;
00208 #else
00209     static const size_t HEIGHT;
00210     static const size_t WIDTH;
00211     static const size_t CAP;
00212 #endif
00213     typedef R storage_t;
00214     typedef typename fmat_internal::unconst<R>::type out_t;
00215     
00216     explicit SubVector(R* x) : data(x) {}
00217     // allow implicit casts for same size
00218     SubVector(const SubVector& x) : data(x.data) {}
00219     SubVector(Matrix<N,1,out_t>& x) : data(x.data) {}
00220     SubVector(Matrix<1,(N==1?0U:N),out_t>& x) : data(x.data) {} // funny template to avoid duplicate constructor for <1,1>
00221     template<typename T> SubVector(const Matrix<N,1,T>& x) : data(x.data) {}
00222     template<typename T> SubVector(const Matrix<1,(N==1?0U:N),T>& x) : data(x.data) {} // funny template to avoid duplicate constructor for <1,1>
00223 
00224     //! this constructor handles shrinking/slicing from other SubVectors
00225     /*! If @a x has const data and this is non-const, we rely on an error on the #data initializer to point that out */
00226     template<size_t S, typename T> explicit SubVector(const SubVector<S,T>& x, size_t offset=0) : data(&x[offset]) {
00227       (void)sizeof(fmat_internal::CompileTimeAssert<SubVector_is_longer_than_source,(N<=S)>);
00228     }
00229     
00230     //! this constructor handles shrinking/slicing from non-const rows
00231     template<size_t S> explicit SubVector(Matrix<1,S,out_t>& x, size_t offset=0) : data(&x.data[offset]) {
00232       (void)sizeof(fmat_internal::CompileTimeAssert<SubVector_is_longer_than_source,(N<=S)>);
00233     }
00234     //! this constructor handles shrinking/slicing from non-const columns
00235     template<size_t S> explicit SubVector(Matrix<S,1,out_t>& x, size_t offset=0) : data(&x.data[offset]) {
00236       (void)sizeof(fmat_internal::CompileTimeAssert<SubVector_is_longer_than_source,(N<=S)>);
00237     }
00238     //! this constructor handles shrinking/slicing from const rows (which can only be used if R is const too - error on #data init otherwise)
00239     template<size_t S, typename T> explicit SubVector(const Matrix<1,S,T>& x, size_t offset=0) : data(&x.data[offset]) {
00240       (void)sizeof(fmat_internal::CompileTimeAssert<SubVector_is_longer_than_source,(N<=S)>);
00241     }
00242     //! this constructor handles shrinking/slicing from const columns (which can only be used if R is const too - error on #data init otherwise)
00243     template<size_t S, typename T> explicit SubVector(const Matrix<S,1,T>& x, size_t offset=0) : data(&x.data[offset]) {
00244       (void)sizeof(fmat_internal::CompileTimeAssert<SubVector_is_longer_than_source,(N<=S)>);
00245     }
00246   
00247     operator SubVector<N,const R>() const { return SubVector<N,const R>(data); }
00248   
00249     template<typename T> SubVector& importFrom(const T& x) { size_t i=N; while(i!=0) { --i; data[i]=x[i]; } return *this; }
00250     template<typename T> T exportTo() const { T x; size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00251     template<typename T> T& exportTo(T& x) const { size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00252   
00253     const SubVector& operator=(R x) const { fmat_internal::tmemset<R>(data,x,N); return *this; }
00254     const SubVector& operator=(const R* x) const { fmat_internal::tmemcpy<R>(data,x,N); return *this; }
00255     const SubVector& operator=(const Matrix<N,1,out_t>& x) const { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00256     const SubVector& operator=(const SubVector& x) const { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00257     template<typename T> const SubVector& operator=(const SubVector<N,T>& x) const { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00258     
00259     const SubVector& operator+=(R x) const { size_t i=N; while(i!=0) data[--i]+=x; return *this; }
00260     const SubVector& operator-=(R x) const { size_t i=N; while(i!=0) data[--i]-=x; return *this; }
00261     const SubVector& operator*=(R x) const { size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00262     const SubVector& operator/=(R x) const { x=1/x; size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00263     Column<N,out_t> operator+(R x) const { return Column<N,out_t>(*this)+=x; }
00264     Column<N,out_t> operator-(R x) const { return Column<N,out_t>(*this)-=x; }
00265     Column<N,out_t> operator*(R x) const { return Column<N,out_t>(*this)*=x; }
00266     Column<N,out_t> operator/(R x) const { return Column<N,out_t>(*this)/=x; }
00267     Column<N,out_t> operator-() const { Column<N,out_t> ans(*this); size_t i=N; while(i--!=0) ans.data[i]=-ans.data[i]; return ans; }
00268     
00269     friend Column<N,out_t> operator+(R x, const SubVector& a) { return a+x; }
00270     friend Column<N,out_t> operator-(R x, const SubVector& a) { return (-a)+x; }
00271     friend Column<N,out_t> operator*(R x, const SubVector& a) { return a*x; }
00272     
00273     template<typename T> const SubVector& operator+=(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; data[i]+=x.data[i]; } return *this; }
00274     template<typename T> const SubVector& operator-=(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; data[i]-=x.data[i]; } return *this; }
00275     template<typename T> const SubVector& operator+=(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; data[i]+=x.data[i]; } return *this; }
00276     template<typename T> const SubVector& operator-=(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; data[i]-=x.data[i]; } return *this; }
00277     template<typename T> Column<N,out_t> operator+(const Matrix<N,1,T>& x) const { return Column<N,out_t>(*this)+=x; }
00278     template<typename T> Column<N,out_t> operator-(const Matrix<N,1,T>& x) const { return Column<N,out_t>(*this)-=x; }
00279     template<typename T> Column<N,out_t> operator+(const SubVector<N,T>& x) const { return Column<N,out_t>(*this)+=x; }
00280     template<typename T> Column<N,out_t> operator-(const SubVector<N,T>& x) const { return Column<N,out_t>(*this)-=x; }
00281   
00282     template<typename T> bool operator==(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
00283     template<typename T> bool operator!=(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
00284     template<typename T> bool operator<(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
00285     template<typename T> bool operator==(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
00286     template<typename T> bool operator!=(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
00287     template<typename T> bool operator<(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
00288   
00289     //! returns true if all elements are less than the corresponding element
00290     template<typename T> bool operator<<(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; if(x.data[i] <= data[i]) return false; } return true; }
00291     template<typename T> bool operator<<(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; if(x.data[i] <= data[i]) return false; } return true; }
00292     
00293     inline R& operator[](size_t i) const { return data[i]; }
00294     
00295     out_t norm() const { out_t ans=0; size_t i=N; while(i!=0) { const R x=data[--i]; ans+=x*x; } return std::sqrt(ans); }
00296     out_t sum() const { out_t ans=0; size_t i=N; while(i!=0) { ans+=data[--i]; } return ans; }
00297     out_t sumSq() const { out_t ans=0; size_t i=N; while(i!=0) { const R x=data[--i]; ans+=x*x; } return ans; }
00298     void abs() const { size_t i=N; while(i!=0) { --i; data[i]=std::abs(data[i]); } }
00299     out_t max() const { if(N==0) return out_t(); out_t ans=data[N-1]; size_t i=N-1; while(i--!=0) if(ans<data[i]) ans=data[i]; return ans; }
00300     out_t min() const { if(N==0) return out_t(); out_t ans=data[N-1]; size_t i=N-1; while(i--!=0) if(ans>data[i]) ans=data[i]; return ans; }
00301     template<typename F> void apply(const F& f) const { size_t i=N; while(i--!=0) data[i]=f(data[i]); }
00302     template<typename F> Column<N,out_t> map(const F& f) const { Column<N,out_t> ans; size_t i=N; while(i--!=0) ans.data[i]=f(data[i]); return ans; }
00303     
00304     template<typename T> void minimize(const Matrix<N,1,T>& x) { size_t i=N; while(i!=0) { --i; if(x.data[i] < data[i]) data[i]=x.data[i]; } }
00305     template<typename T> void minimize(const SubVector<N,T>& x) { size_t i=N; while(i!=0) { --i; if(x.data[i] < data[i]) data[i]=x.data[i]; } }
00306     template<typename T> void maximize(const Matrix<N,1,T>& x) { size_t i=N; while(i!=0) { --i; if(data[i] < x.data[i]) data[i]=x.data[i]; } }
00307     template<typename T> void maximize(const SubVector<N,T>& x) { size_t i=N; while(i!=0) { --i; if(data[i] < x.data[i]) data[i]=x.data[i]; } }
00308         
00309     inline Row<N,out_t> transpose() const ATTR_must_check {
00310       Row<N,out_t> ans=fmat_internal::NoInit();
00311       fmat_internal::tmemcpy<out_t>(ans.data,data,N);
00312       return ans;
00313     }
00314 
00315     inline std::string fmt(std::string const &numberFormat=defaultNumberFormat, 
00316       std::string const &firstLineStart="{",
00317       std::string const &nextLineStart= "",
00318       std::string const &lastLineEnd=   "}",
00319       std::string const &rowBegin="",
00320       std::string const &elementSep="",
00321       std::string const &rowEnd="",
00322       std::string const &rowSep=" ") const
00323     {
00324       return fullfmt(data,N,1,numberFormat,firstLineStart,nextLineStart,lastLineEnd,rowBegin,elementSep,rowEnd,rowSep);
00325     }
00326 
00327   protected:
00328     SubVector() : data(NULL) {}
00329     R* data;
00330   };
00331   
00332   // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00333 #if !defined(__clang__) && defined(__GNUC__) && !(__GNUC__==4 && __GNUC_MINOR__<1)
00334   template<size_t N, typename R> const size_t SubVector<N,R>::HEIGHT=N;
00335   template<size_t N, typename R> const size_t SubVector<N,R>::WIDTH=1;
00336   template<size_t N, typename R> const size_t SubVector<N,R>::CAP=N;
00337 #endif
00338   
00339   
00340   template<size_t H, size_t W, typename R=fmatReal>
00341   class SubMatrix {
00342     template<size_t MH, size_t MW, typename MR> friend class Matrix;
00343     template<size_t MH, size_t MW, typename MR> friend class SubMatrix;
00344     template<size_t MN, typename MR> friend class SubVector;
00345     template<size_t MN, typename MR> friend class Column;
00346     template<size_t MN, typename MR> friend class Row;
00347   public:
00348     // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00349 #if defined(__clang__) || !defined(__GNUC__) || (__GNUC__==4 && __GNUC_MINOR__<1)
00350     static const size_t HEIGHT=H;
00351     static const size_t WIDTH=W;
00352     static const size_t CAP=H*W;
00353 #else
00354     static const size_t HEIGHT;
00355     static const size_t WIDTH;
00356     static const size_t CAP;
00357 #endif
00358     typedef R storage_t;
00359     typedef typename fmat_internal::unconst<R>::type out_t;
00360     
00361     explicit SubMatrix(R* x, size_t colStride=H) { size_t c=W; while(c--!=0) cols[c].data = &x[c*colStride]; }
00362     // allow implicit casts for same size
00363     SubMatrix(const SubMatrix<H,W,out_t>& x) { size_t c=W; while(c--!=0) cols[c].data = x.cols[c].data; }
00364     SubMatrix(Matrix<H,W,out_t>& x) { size_t c=W; while(c--!=0) cols[c].data = &x.data[c*H]; }
00365     template<typename T> SubMatrix(const SubMatrix<H,W,T>& x) { size_t c=W; while(c--!=0) cols[c].data = x.cols[c].data; }
00366     template<typename T> SubMatrix(const Matrix<H,W,T>& x) { size_t c=W; while(c--!=0) cols[c].data = &x.data[c*H]; }
00367     
00368     //! this constructor handles shrinking/slicing from other SubMatrix, starting at (0,0)
00369     /*! If @a x has const data and this is non-const, we rely on an error on the #cols initializer to point that out */
00370     template<size_t SH, size_t SW, typename T> explicit SubMatrix(const SubMatrix<SH,SW,T>& x) {
00371       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_rows_than_source,(H<=SH)>);
00372       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_columns_than_source,(W<=SW)>);
00373       size_t c=W; while(c--!=0) cols[c].data = x.cols[c].data; 
00374     }
00375     //! this constructor handles shrinking/slicing from other SubMatrix, at a specified offset
00376     /*! If @a x has const data and this is non-const, we rely on an error on the #cols initializer to point that out */
00377     template<size_t SH, size_t SW, typename T> explicit SubMatrix(const SubMatrix<SH,SW,T>& x, size_t rowOff, size_t colOff) {
00378       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_rows_than_source,(H<=SH)>);
00379       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_columns_than_source,(W<=SW)>);
00380       size_t c=W; while(c--!=0) cols[c].data = &x.cols[c+colOff].data[rowOff]; 
00381     }
00382     //! this constructor handles shrinking/slicing from non-const Matrix, starting at (0,0)
00383     template<size_t SH, size_t SW> explicit SubMatrix(Matrix<SH,SW,out_t>& x) {
00384       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_rows_than_source,(H<=SH)>);
00385       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_columns_than_source,(W<=SW)>);
00386       size_t c=W; while(c--!=0) cols[c].data = &x.data[c*SH]; 
00387     }
00388     //! this constructor handles shrinking/slicing from non-const Matrix, starting at specified offset
00389     template<size_t SH, size_t SW> explicit SubMatrix(Matrix<SH,SW,out_t>& x, size_t rowOff, size_t colOff) {
00390       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_rows_than_source,(H<=SH)>);
00391       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_columns_than_source,(W<=SW)>);
00392       size_t c=W; while(c--!=0) cols[c].data = &x.data[(c+colOff)*SH+rowOff];
00393     }
00394     //! this constructor handles shrinking/slicing from const Matrix (which can only be used if R is const too - error on #cols init otherwise)
00395     template<size_t SH, size_t SW, typename T> explicit SubMatrix(const Matrix<SH,SW,T>& x) {
00396       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_rows_than_source,(H<=SH)>);
00397       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_columns_than_source,(W<=SW)>);
00398       size_t c=W; while(c--!=0) cols[c].data = &x.data[c*SH]; 
00399     }
00400     //! this constructor handles shrinking/slicing from const Matrix (which can only be used if R is const too - error on #cols init otherwise)
00401     template<size_t SH, size_t SW, typename T> explicit SubMatrix(const Matrix<SH,SW,T>& x, size_t rowOff, size_t colOff) {
00402       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_rows_than_source,(H<=SH)>);
00403       (void)sizeof(fmat_internal::CompileTimeAssert<SubMatrix_has_more_columns_than_source,(W<=SW)>);
00404       size_t c=W; while(c--!=0) cols[c].data = &x.data[(c+colOff)*SH+rowOff];
00405     }
00406 
00407     operator SubMatrix<H,W,const R>() const { return SubMatrix<H,W,const R>(*this); }
00408 
00409     template<typename T> SubMatrix& importFrom(const T& x) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { cols[c].data[r]=x(r,c); } return *this; }
00410     template<typename T> SubMatrix& importFromCMajor(const T& x, size_t stride=H) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { cols[c].data[r]=x[c*stride+r]; } return *this; }
00411     template<typename T> SubMatrix& importFromRMajor(const T& x, size_t stride=W) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { cols[c].data[r]=x[r*stride+c]; } return *this; }
00412     template<typename T> SubMatrix& importFrom2DArray(const T& x) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { cols[c].data[r]=x[r][c]; } return *this; }
00413     template<typename T> SubMatrix& importFromNewmat(const T& x) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { cols[c].data[r]=x(r+1,c+1); } return *this; }
00414     template<typename T> T exportTo() const { T x; for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x(r,c)=cols[c].data[r]; } return x; }
00415     template<typename T> T& exportTo(T& x) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x(r,c)=cols[c].data[r]; } return x; }
00416     template<typename T> T& exportToCMajor(T& x, size_t stride=H) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x[c*stride+r]=cols[c].data[r]; } return x; }
00417     template<typename T> T& exportToRMajor(T& x, size_t stride=W) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x[r*stride+c]=cols[c].data[r]; } return x; }
00418     template<typename T> T& exportTo2DArray(T& x) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x[r][c]=cols[c].data[r]; } return x; }
00419     template<typename T> T& exportToNewmat(T& x) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x(r+1,c+1)=cols[c].data[r]; } return x; }
00420     
00421     const SubMatrix& operator=(R x) const { size_t c=W; while(c!=0) cols[--c]=x; return *this; }
00422     const SubMatrix& operator=(const R* x) const { size_t c=W; while(c--!=0) cols[c]=&x[c*H]; return *this; }
00423     const SubMatrix& operator=(const Matrix<H,W,out_t>& x) const { size_t c=W; while(c--!=0) cols[c]=&x.data[c*H]; return *this; }
00424     const SubMatrix& operator=(const SubMatrix& x) const { size_t c=W; while(c--!=0) cols[c]=x.cols[c]; return *this; }
00425     // this can't convert types, but handles assignment to const R from non-const R (without duplicating assignment above)
00426     template<typename T> const SubMatrix& operator=(const SubMatrix<H,W,T>& x) const { size_t c=W; while(c--!=0) cols[c]=x.cols[c]; return *this; }
00427     
00428     const SubMatrix& operator+=(R x) const { size_t c=W; while(c!=0) cols[--c]+=x; return *this; }
00429     const SubMatrix& operator-=(R x) const { size_t c=W; while(c!=0) cols[--c]-=x; return *this; }
00430     const SubMatrix& operator*=(R x) const { size_t c=W; while(c!=0) cols[--c]*=x; return *this; }
00431     const SubMatrix& operator/=(R x) const { x=1/x; size_t c=W; while(c!=0) cols[--c]*=x; return *this; }
00432     Matrix<H,W,out_t> operator+(R x) const { return Matrix<H,W,out_t>(*this)+=x; }
00433     Matrix<H,W,out_t> operator-(R x) const { return Matrix<H,W,out_t>(*this)-=x; }
00434     Matrix<H,W,out_t> operator*(R x) const { return Matrix<H,W,out_t>(*this)*=x; }
00435     Matrix<H,W,out_t> operator/(R x) const { return Matrix<H,W,out_t>(*this)/=x; }
00436     Matrix<H,W,out_t> operator-() const { Matrix<H,W,out_t> ans(*this); size_t i=H*W; while(i--!=0) ans.data[i]=-ans.data[i]; return ans; }
00437     
00438     friend Matrix<H,W,out_t> operator+(R x, const SubMatrix& a) { return a+x; }
00439     friend Matrix<H,W,out_t> operator-(R x, const SubMatrix& a) { return (-a)+x; }
00440     friend Matrix<H,W,out_t> operator*(R x, const SubMatrix& a) { return a*x; }
00441     
00442     template<typename T> const SubMatrix& operator+=(const SubMatrix<H,W,T>& x) const { size_t c=W; while(c--!=0) cols[c]+=x.cols[c]; return *this; }
00443     template<typename T> const SubMatrix& operator-=(const SubMatrix<H,W,T>& x) const { size_t c=W; while(c--!=0) cols[c]-=x.cols[c]; return *this; }
00444     template<typename T> const SubMatrix& operator+=(const Matrix<H,W,T>& x) const {
00445       for(size_t c=W; c--!=0;) {
00446         const T * const tmp = &x.data[c*H];
00447         for(size_t r=H; r--!=0;)
00448           cols[c].data[r]+=tmp[r];
00449       }
00450       return *this;
00451     }
00452     template<typename T> const SubMatrix& operator-=(const Matrix<H,W,T>& x) const {
00453       for(size_t c=W; c--!=0;) {
00454         const T * const tmp = &x.data[c*H];
00455         for(size_t r=H; r--!=0;)
00456           cols[c].data[r]-=tmp[r];
00457       }
00458       return *this;
00459     }
00460     template<typename T> Matrix<H,W,out_t> operator+(const SubMatrix<H,W,T>& x) const { return Matrix<H,W,out_t>(*this)+=x; }
00461     template<typename T> Matrix<H,W,out_t> operator-(const SubMatrix<H,W,T>& x) const { return Matrix<H,W,out_t>(*this)-=x; }
00462     template<typename T> Matrix<H,W,out_t> operator+(const Matrix<H,W,T>& x) const { return Matrix<H,W,out_t>(*this)+=x; }
00463     template<typename T> Matrix<H,W,out_t> operator-(const Matrix<H,W,T>& x) const { return Matrix<H,W,out_t>(*this)-=x; }
00464     
00465     template<typename T> bool operator==(const SubMatrix<H,W,T>& x) const { size_t c=W; while(c!=0) { --c; if(cols[c]!=x.cols[c]) return false; } return true; }
00466     template<typename T> bool operator!=(const SubMatrix<H,W,T>& x) const { size_t c=W; while(c!=0) { --c; if(cols[c]!=x.cols[c]) return true; } return false; }
00467     template<typename T> bool operator==(const Matrix<H,W,T>& x) const { size_t c=W; while(c!=0) { --c; if(cols[c]!=x.column(c)) return false; } return true; }
00468     template<typename T> bool operator!=(const Matrix<H,W,T>& x) const { size_t c=W; while(c!=0) { --c; if(cols[c]!=x.column(c)) return true; } return false; }
00469 
00470     inline R& operator()(size_t r, size_t c) { return cols[c].data[r]; }
00471     inline const R& operator()(size_t r, size_t c) const { return cols[c].data[r]; }
00472     
00473     inline SubVector<H,R>& column(size_t i) { return cols[i]; }
00474     inline const SubVector<H,R>& column(size_t i) const { return cols[i]; }
00475     
00476     inline SubMatrix<1,W,R> row(size_t i) { return SubMatrix<1,W,R>(*this,i,0); }
00477     inline SubMatrix<1,W,const R> row(size_t i) const { return SubMatrix<1,W,const R>(*this,i,0); }
00478 
00479     Column<H,R> minC() const {
00480       if(CAP==0) return Column<H,R>();
00481       Column<H,R> ans = cols[0];
00482       size_t c=W; while(--c!=0) { size_t r=H; while(r!=0) { --r; if(cols[c].data[r]<ans[r]) ans[r]=cols[c].data[r]; } }
00483       return ans;
00484     }
00485     
00486     Column<H,R> maxC() const {
00487       if(CAP==0) return Column<H,R>();
00488       Column<H,R> ans = cols[0];
00489       size_t c=W; while(--c!=0) { size_t r=H; while(r!=0) { --r; if(ans[r]<cols[c].data[r]) ans[r]=cols[c].data[r]; } }
00490       return ans;
00491     }
00492     Row<W,R> minR() const { Row<W,R> ans=fmat_internal::NoInit(); size_t c=W; while(c!=0) { --c; ans[c]=cols[c].min(); } return ans; }
00493     Row<W,R> maxR() const { Row<W,R> ans=fmat_internal::NoInit(); size_t c=W; while(c!=0) { --c; ans[c]=cols[c].max(); } return ans; }
00494     void abs() const { size_t c=W; while(c!=0) cols[--c].abs(); }
00495     template<typename F> void apply(const F& f) const { size_t c=W; while(c--!=0) cols[c].apply(f); }
00496     template<typename F> Matrix<H,W,out_t> map(const F& f) const {
00497       if(H==0 || W==0) return Matrix<H,W,out_t>();
00498       Matrix<H,W,out_t> ans=fmat_internal::NoInit();
00499       size_t c=W; while(c!=0) { --c; size_t r=H; while(r!=0) { --r; ans.data[c*H+r] = f(cols[c].data[r]); } }
00500       return ans;
00501     }
00502     
00503     inline Matrix<W,H,out_t> transpose() const ATTR_must_check {
00504       Matrix<W,H,out_t> ans=fmat_internal::NoInit();
00505       for(size_t c=W; c--!=0;)
00506         for(size_t r=H; r--!=0;)
00507           ans.data[r*W+c]=cols[c].data[r];
00508       return ans;
00509     }
00510 
00511     std::string fmt(std::string const &numberFormat=defaultNumberFormat, 
00512       std::string const &firstLineStart="{ ",
00513       std::string const &nextLineStart= "  ",
00514       std::string const &lastLineEnd=   " }",
00515       std::string const &rowBegin="",
00516       std::string const &elementSep=" ",
00517       std::string const &rowEnd="",
00518       std::string const &rowSep="\n") const
00519     {
00520       Matrix<H,W,out_t> m(*this); // copy to a matrix so the data is all together for fullfmt... not ideal, but this is rarely used
00521       return fullfmt(m.data,H,W,numberFormat,firstLineStart,nextLineStart,lastLineEnd,rowBegin,elementSep,rowEnd,rowSep);
00522     }
00523 
00524   protected:
00525     SubVector<H,R> cols[(W==0)?1:W]; // funny definition is for older compilers that don't like 0-sized arrays
00526   };
00527   // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00528 #if !defined(__clang__) && defined(__GNUC__) && !(__GNUC__==4 && __GNUC_MINOR__<1)
00529   template<size_t H, size_t W, typename R> const size_t SubMatrix<H,W,R>::HEIGHT=H;
00530   template<size_t H, size_t W, typename R> const size_t SubMatrix<H,W,R>::WIDTH=W;
00531   template<size_t H, size_t W, typename R> const size_t SubMatrix<H,W,R>::CAP=H*W;
00532 #endif
00533   
00534   
00535   template<size_t H, size_t W, typename R=fmatReal>
00536   class Matrix {
00537     template<size_t MH, size_t MW, typename MR> friend class Matrix;
00538     template<size_t MH, size_t MW, typename MR> friend class SubMatrix;
00539     template<size_t MN, typename MR> friend class SubVector;
00540     template<size_t MN, typename MR> friend class Column;
00541     template<size_t MN, typename MR> friend class Row;
00542   public:
00543     // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00544 #if defined(__clang__) || !defined(__GNUC__) || (__GNUC__==4 && __GNUC_MINOR__<1)
00545     static const size_t HEIGHT=H;
00546     static const size_t WIDTH=W;
00547     static const size_t CAP=H*W;
00548 #else
00549     static const size_t HEIGHT;
00550     static const size_t WIDTH;
00551     static const size_t CAP;
00552 #endif
00553     typedef R storage_t;
00554     typedef typename fmat_internal::unconst<R>::type out_t;
00555     
00556     Matrix(const fmat_internal::NoInit&) {}
00557     
00558     Matrix() { memset(data,0,sizeof(R)*CAP); }
00559     explicit Matrix(const R x) { fmat_internal::tmemset<R>(data,x,CAP); }
00560     explicit Matrix(const R* x, size_t colStride=H) { size_t c=W; while(c--!=0) fmat_internal::tmemcpy<R>(&data[c*H],&x[c*colStride],H); }
00561     Matrix(const SubMatrix<H,W,out_t>& x) { size_t c=W; while(c--!=0) fmat_internal::tmemcpy<R>(&data[c*H],x.cols[c].data,H); }
00562     Matrix(const SubMatrix<H,W,const out_t>& x) { size_t c=W; while(c--!=0) fmat_internal::tmemcpy<R>(&data[c*H],x.cols[c].data,H); }
00563     Matrix(const Matrix<H,W,out_t>& x) { fmat_internal::tmemcpy<R>(data,x.data,CAP); }
00564     Matrix(const Matrix<H,W,const out_t>& x) { fmat_internal::tmemcpy<R>(data,x.data,CAP); }
00565 
00566     template<size_t SH, size_t SW, typename T> explicit Matrix(const SubMatrix<SH,SW,T>& x) {
00567       memset(data,0,sizeof(R)*CAP);
00568       size_t toCopy = std::min(H,SH);
00569       size_t c = std::min(W,SW);
00570       while(c--!=0) 
00571         fmat_internal::tmemcpy<R>(&data[c*H],&x.cols[c][0],toCopy);
00572     }
00573     template<size_t SH, size_t SW, typename T> explicit Matrix(const SubMatrix<SH,SW,T>& x, size_t rowOff, size_t colOff) {
00574       memset(data,0,sizeof(R)*CAP);
00575       size_t toCopy = std::min(H,SH-rowOff);
00576       size_t c = std::min(W,SW-colOff);
00577       while(c--!=0) 
00578         fmat_internal::tmemcpy<R>(&data[c*H],&x.cols[c+colOff][rowOff],toCopy);
00579     }
00580     template<size_t SH, size_t SW> explicit Matrix(const Matrix<SH,SW,R>& x) {
00581       memset(data,0,sizeof(R)*CAP);
00582       size_t toCopy = std::min(H,SH);
00583       size_t c = std::min(W,SW);
00584       while(c--!=0) 
00585         fmat_internal::tmemcpy<R>(&data[c*H],&x.data[c*SH],toCopy);
00586     }
00587     template<size_t SH, size_t SW> explicit Matrix(const Matrix<SH,SW,R>& x, size_t rowOff, size_t colOff) {
00588       memset(data,0,sizeof(R)*CAP);
00589       size_t toCopy = std::min(H,SH-rowOff);
00590       size_t c = std::min(W,SW-colOff);
00591       while(c--!=0) 
00592         fmat_internal::tmemcpy<R>(&data[c*H],&x.data[(c+colOff)*SH+rowOff],toCopy);
00593     }
00594     
00595     // we want to avoid introducing any 'virtual' to maximize performance
00596     //virtual ~Matrix() {}
00597     
00598     static const Matrix& identity() { static IdentityMatrix<H,W,R> ident; return ident; }
00599     
00600     template<typename T> Matrix& importFrom(const T& x) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { data[c*H+r]=x(r,c); } return *this; }
00601     template<typename T> Matrix& importFromCMajor(const T& x, size_t stride=H) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { data[c*H+r]=x[c*stride+r]; } return *this; }
00602     template<typename T> Matrix& importFromRMajor(const T& x, size_t stride=W) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { data[c*H+r]=x[r*stride+c]; } return *this; }
00603     template<typename T> Matrix& importFrom2DArray(const T& x) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { data[c*H+r]=x[r][c]; } return *this; }
00604     template<typename T> Matrix& importFromNewmat(const T& x) { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { data[c*H+r]=x(r+1,c+1); } return *this; }
00605     template<typename T> T exportTo() const { T x; for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x(r,c)=data[c*H+r]; } return x; }
00606     template<typename T> T& exportTo(T& x) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x(r,c)=data[c*H+r]; } return x; }
00607     template<typename T> T& exportToCMajor(T& x, size_t stride=H) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x[c*stride+r]=data[c*H+r]; } return x; }
00608     template<typename T> T& exportToRMajor(T& x, size_t stride=W) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x[r*stride+c]=data[c*H+r]; } return x; }
00609     template<typename T> T& exportTo2DArray(T& x) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x[r][c]=data[c*H+r]; } return x; }
00610     template<typename T> T& exportToNewmat(T& x) const { for(size_t c=0; c<W; ++c) for(size_t r=0; r<H; ++r) { x((int)r+1,(int)c+1)=data[c*H+r]; } return x; }
00611     
00612     Matrix& operator=(const R* x) { fmat_internal::tmemcpy<R>(data,x,CAP); return *this; }
00613     Matrix& operator=(R x) { fmat_internal::tmemset<R>(data,x,CAP); return *this; }
00614     Matrix& operator=(const SubMatrix<H,W,R>& x) { size_t c=W; while(c--!=0) fmat_internal::tmemcpy<R>(&data[c*H],x.cols[c].data,H); return *this; }
00615     Matrix& operator=(const Matrix<H,W,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,CAP); return *this; }
00616     
00617     Matrix& operator+=(R x) { size_t i=CAP; while(i!=0) data[--i]+=x; return *this; }
00618     Matrix& operator-=(R x) { size_t i=CAP; while(i!=0) data[--i]-=x; return *this; }
00619     Matrix& operator*=(R x) { size_t i=CAP; while(i!=0) data[--i]*=x; return *this; }
00620     Matrix& operator/=(R x) { x=1/x; size_t i=CAP; while(i!=0) data[--i]*=x; return *this; }
00621     Matrix<H,W,out_t> operator+(R x) const { return Matrix<H,W,out_t>(*this)+=x; }
00622     Matrix<H,W,out_t> operator-(R x) const { return Matrix<H,W,out_t>(*this)-=x; }
00623     Matrix<H,W,out_t> operator*(R x) const { return Matrix<H,W,out_t>(*this)*=x; }
00624     Matrix<H,W,out_t> operator/(R x) const { return Matrix<H,W,out_t>(*this)/=x; }
00625     Matrix<H,W,out_t> operator-() const { Matrix<H,W,out_t> ans(*this); size_t i=H*W; while(i--!=0) ans.data[i]=-ans.data[i]; return ans; }
00626     
00627     friend Matrix<H,W,out_t> operator+(R x, const Matrix& a) { return a+x; }
00628     friend Matrix<H,W,out_t> operator-(R x, const Matrix& a) { return (-a)+x; }
00629     friend Matrix<H,W,out_t> operator*(R x, const Matrix& a) { return a*x; }
00630     
00631     Matrix& operator+=(const SubMatrix<H,W,out_t>& x) {
00632       for(size_t c=W; c--!=0;) {
00633         R * const tmp = &data[c*H];
00634         for(size_t r=H; r--!=0;)
00635           tmp[r]+=x.cols[c].data[r];
00636       }
00637       return *this;
00638     }
00639     Matrix& operator-=(const SubMatrix<H,W,out_t>& x) {
00640       for(size_t c=W; c--!=0;) {
00641         R * const tmp = &data[c*H];
00642         for(size_t r=H; r--!=0;)
00643           tmp[r]-=x.cols[c].data[r];
00644       }
00645       return *this;
00646     }
00647     Matrix& operator+=(const SubMatrix<H,W,const out_t>& x) {
00648       for(size_t c=W; c--!=0;) {
00649         R * const tmp = &data[c*H];
00650         for(size_t r=H; r--!=0;)
00651           tmp[r]+=x.cols[c].data[r];
00652       }
00653       return *this;
00654     }
00655     Matrix& operator-=(const SubMatrix<H,W,const out_t>& x) {
00656       for(size_t c=W; c--!=0;) {
00657         R * const tmp = &data[c*H];
00658         for(size_t r=H; r--!=0;)
00659           tmp[r]-=x.cols[c].data[r];
00660       }
00661       return *this;
00662     }
00663     Matrix& operator+=(const Matrix<H,W,R>& x) { size_t i=CAP; while(i--!=0) data[i]+=x.data[i]; return *this; }
00664     Matrix& operator-=(const Matrix<H,W,R>& x) { size_t i=CAP; while(i--!=0) data[i]-=x.data[i]; return *this; }
00665     Matrix<H,W,R> operator+(const SubMatrix<H,W,R>& x) const { return Matrix<H,W,R>(*this)+=x; }
00666     Matrix<H,W,R> operator-(const SubMatrix<H,W,R>& x) const { return Matrix<H,W,R>(*this)-=x; }
00667     Matrix<H,W,R> operator+(const Matrix<H,W,R>& x) const { return Matrix<H,W,R>(*this)+=x; }
00668     Matrix<H,W,R> operator-(const Matrix<H,W,R>& x) const { return Matrix<H,W,R>(*this)-=x; }
00669     
00670     bool operator==(const SubMatrix<H,W,R>& x) const { size_t c=W; while(c!=0) { --c; if(column(c)!=x.cols[c]) return false; } return true; }
00671     bool operator!=(const SubMatrix<H,W,R>& x) const { size_t c=W; while(c!=0) { --c; if(column(c)!=x.cols[c]) return true; } return false; }
00672     bool operator==(const Matrix<H,W,R>& x) const { size_t i=H*W; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
00673     bool operator!=(const Matrix<H,W,R>& x) const { size_t i=H*W; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
00674 
00675     inline R& operator()(size_t r, size_t c) { return data[c*H+r]; }
00676     inline const R& operator()(size_t r, size_t c) const { return data[c*H+r]; }
00677     
00678     inline SubVector<H,R> column(size_t i) { return SubVector<H,R>(&data[i*H]); }
00679     inline const SubVector<H,const R> column(size_t i) const { return SubVector<H,const R>(&data[i*H]); }
00680 
00681     inline SubMatrix<1,W,R> row(size_t i) { return SubMatrix<1,W,R>(data+i, H); }
00682     inline const SubMatrix<1,W,const R> row(size_t i) const { return SubMatrix<1,W,const R>(data+i, H); }
00683     
00684     Column<H,R> minC() const {
00685       if(CAP==0) return Column<H,R>();
00686       Column<H,R> ans(data);
00687       size_t c=W; while(--c!=0) { size_t r=H; while(r!=0) { --r; if(data[c*H+r]<ans[r]) ans[r]=data[c*H+r]; } }
00688       return ans;
00689     }
00690     
00691     Column<H,R> maxC() const {
00692       if(CAP==0) return Column<H,R>();
00693       Column<H,R> ans(data);
00694       size_t c=W; while(--c!=0) { size_t r=H; while(r!=0) { --r; if(ans[r]<data[c*H+r]) ans[r]=data[c*H+r]; } }
00695       return ans;
00696     }
00697     Row<W,R> minR() const { Row<W,R> ans=fmat_internal::NoInit(); size_t c=W; while(c!=0) { --c; ans[c]=column(c).min(); } return ans; }
00698     Row<W,R> maxR() const { Row<W,R> ans=fmat_internal::NoInit(); size_t c=W; while(c!=0) { --c; ans[c]=column(c).max(); } return ans; }
00699     void abs() { size_t i=CAP; while(i!=0) { --i; data[i]=std::abs(data[i]); } }
00700     template<typename F> void apply(const F& f) { size_t i=H*W; while(i!=0) { --i;  data[i] = f(data[i]); } }
00701     template<typename F> Matrix map(const F& f) const {
00702       if(H==0 || W==0) return Matrix();
00703       Matrix ans=fmat_internal::NoInit();
00704       size_t i=H*W; while(i!=0) { --i;  ans.data[i] = f(data[i]); }
00705       return ans;
00706     }
00707     
00708     inline Matrix<W,H,R> transpose() const ATTR_must_check {
00709       Matrix<W,H,R> ans=fmat_internal::NoInit();
00710       for(size_t c=W; c--!=0;)
00711         for(size_t r=H; r--!=0;)
00712           ans.data[r*W+c]=data[c*H+r];
00713       return ans;
00714     }
00715     
00716     inline std::string fmt(std::string const &numberFormat=defaultNumberFormat, 
00717       std::string const &firstLineStart="[ ",
00718       std::string const &nextLineStart= "  ",
00719       std::string const &lastLineEnd=   " ]",
00720       std::string const &rowBegin="",
00721       std::string const &elementSep=" ",
00722       std::string const &rowEnd="",
00723       std::string const &rowSep="\n") const
00724     {
00725       return fullfmt(&data[0],H,W,numberFormat,firstLineStart,nextLineStart,lastLineEnd,rowBegin,elementSep,rowEnd,rowSep);
00726     }
00727 
00728   protected:
00729     R data[(H*W==0)?1:H*W]; // funny definition is for older compilers that don't like 0-sized arrays
00730     
00731     template<size_t HH, size_t WW, typename RR=fmatReal>
00732     struct IdentityMatrix : Matrix<HH,WW,RR> {
00733       IdentityMatrix() : Matrix() {
00734         size_t d = std::min(H,W);
00735         for(size_t i=0; i<d; ++i)
00736           this->data[i*H+i]=1;
00737       }
00738     };
00739 
00740   };
00741   // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00742 #if !defined(__clang__) && defined(__GNUC__) && !(__GNUC__==4 && __GNUC_MINOR__<1)
00743   template<size_t H, size_t W, typename R> const size_t Matrix<H,W,R>::HEIGHT=H;
00744   template<size_t H, size_t W, typename R> const size_t Matrix<H,W,R>::WIDTH=W;
00745   template<size_t H, size_t W, typename R> const size_t Matrix<H,W,R>::CAP=H*W;
00746 #endif
00747   
00748   
00749   template<size_t N, typename R=fmatReal>
00750   class Column : public Matrix<N,1,R> {
00751     template<size_t S, typename T> friend class SubVector;
00752     template<size_t S, typename T> friend class Column;
00753     template<size_t S, typename T> friend class Row;
00754     friend Column<2,R> packT<>(R x, R y);
00755     friend Column<3,R> packT<>(R x, R y, R z);
00756     friend Column<4,R> packT<>(R x, R y, R z, R d);
00757     friend Column<2,fmatReal> pack(fmatReal x, fmatReal y);
00758     friend Column<3,fmatReal> pack(fmatReal x, fmatReal y, fmatReal z);
00759     friend Column<4,fmatReal> pack(fmatReal x, fmatReal y, fmatReal z, fmatReal d);
00760   public:
00761     // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00762 #if defined(__clang__) || !defined(__GNUC__) || (__GNUC__==4 && __GNUC_MINOR__<1)
00763     static const size_t HEIGHT=N;
00764     static const size_t WIDTH=1;
00765     static const size_t CAP=N;
00766 #else
00767     static const size_t HEIGHT;
00768     static const size_t WIDTH;
00769     static const size_t CAP;
00770 #endif
00771     typedef R storage_t;
00772     typedef typename fmat_internal::unconst<R>::type out_t;
00773     
00774     Column(const fmat_internal::NoInit& noinit) : Matrix<N,1,R>(noinit) {}
00775     
00776     Column() : Matrix<N,1,R>() {}
00777     explicit Column(const R x) : Matrix<N,1,R>(x) {}
00778     explicit Column(const R* x, size_t stride=sizeof(R)) : Matrix<N,1,R>(fmat_internal::NoInit()) { size_t i=N; while(i!=0) { --i; data[i]=x[i*stride/sizeof(R)]; } }
00779     Column(const SubVector<N,R>& x) : Matrix<N,1,R>(x.data) {}
00780     Column(const SubVector<N,const R>& x) : Matrix<N,1,R>(x.data) {}
00781     Column(const SubMatrix<N,1,R>& x) : Matrix<N,1,R>(x) {}
00782     Column(const SubMatrix<N,1,const R>& x) : Matrix<N,1,R>(x) {}
00783     Column(const Matrix<N,1,R>& x) : Matrix<N,1,R>(x) {}
00784     template<size_t S> explicit Column(const Column<S,R>& x, size_t srcOffset=0) : Matrix<N,1,R>() {
00785       size_t toCopy = std::min(N,S-srcOffset);
00786       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00787     }
00788     template<size_t S> explicit Column(const SubVector<S,R>& x, size_t srcOffset=0) : Matrix<N,1,R>() {
00789       size_t toCopy = std::min(N,S-srcOffset);
00790       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00791     }
00792     template<size_t S> explicit Column(const SubVector<S,const R>& x, size_t srcOffset=0) : Matrix<N,1,R>() {
00793       size_t toCopy = std::min(N,S-srcOffset);
00794       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00795     }
00796     template<typename T> Column& importFrom(const T& x) { size_t i=N; while(i!=0) { --i; data[i]=x[i]; } return *this; }
00797     template<typename T> T exportTo() const { T x; size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00798     template<typename T> T& exportTo(T& x) const { size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00799     // provided by implicit SubVector constructors
00800     //operator SubVector<N,R>() { return SubVector<N,R>(data); }
00801     //operator SubVector<N,const R>() const { return SubVector<N,const R>(data); }
00802     
00803     Column& operator=(const R* x) { fmat_internal::tmemcpy<R>(data,x,CAP); return *this; }
00804     Column& operator=(R x) { fmat_internal::tmemset<R>(data,x,CAP); return *this; }
00805     Column& operator=(const SubVector<N,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00806     Column& operator=(const SubVector<N,const R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00807     Column& operator=(const SubMatrix<N,1,R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00808     Column& operator=(const SubMatrix<N,1,const R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00809     Column& operator=(const Matrix<N,1,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,CAP); return *this; }
00810     
00811     Column& operator+=(R x) { size_t i=N; while(i!=0) data[--i]+=x; return *this; }
00812     Column& operator-=(R x) { size_t i=N; while(i!=0) data[--i]-=x; return *this; }
00813     Column& operator*=(R x) { size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00814     Column& operator/=(R x) { x=1/x; size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00815     Column<N,out_t> operator+(R x) const { return Column<N,out_t>(*this)+=x; }
00816     Column<N,out_t> operator-(R x) const { return Column<N,out_t>(*this)-=x; }
00817     Column<N,out_t> operator*(R x) const { return Column<N,out_t>(*this)*=x; }
00818     Column<N,out_t> operator/(R x) const { return Column<N,out_t>(*this)/=x; }
00819     Column<N,out_t> operator-() const { Column<N,out_t> ans(*this); size_t i=N; while(i--!=0) ans.data[i]=-ans.data[i]; return ans; }
00820     
00821     friend Column<N,out_t> operator+(R x, const Column& a) { return a+x; }
00822     friend Column<N,out_t> operator-(R x, const Column& a) { return (-a)+x; }
00823     friend Column<N,out_t> operator*(R x, const Column& a) { return a*x; }
00824     
00825     Column& operator+=(const SubVector<N,R>& x) { size_t i=CAP; while(i--!=0) data[i]+=x.data[i]; return *this; }
00826     Column& operator-=(const SubVector<N,R>& x) { size_t i=CAP; while(i--!=0) data[i]-=x.data[i]; return *this; }
00827     Column& operator+=(const SubVector<N,const R>& x) { size_t i=CAP; while(i--!=0) data[i]+=x.data[i]; return *this; }
00828     Column& operator-=(const SubVector<N,const R>& x) { size_t i=CAP; while(i--!=0) data[i]-=x.data[i]; return *this; }
00829     Column& operator+=(const SubMatrix<N,1,R>& x) { Matrix<N,1,R>::operator+=(x); return *this;}
00830     Column& operator-=(const SubMatrix<N,1,R>& x) { Matrix<N,1,R>::operator-=(x); return *this;}
00831     Column& operator+=(const SubMatrix<N,1,const R>& x) { Matrix<N,1,R>::operator+=(x); return *this;}
00832     Column& operator-=(const SubMatrix<N,1,const R>& x) { Matrix<N,1,R>::operator-=(x); return *this;}
00833     Column& operator+=(const Matrix<N,1,R>& x) { Matrix<N,1,R>::operator+=(x); return *this;}
00834     Column& operator-=(const Matrix<N,1,R>& x) { Matrix<N,1,R>::operator-=(x); return *this;}
00835     
00836     Column operator+(const SubVector<N,R>& x) const { return Column(*this)+=x; }
00837     Column operator-(const SubVector<N,R>& x) const { return Column(*this)-=x; }
00838     Column operator+(const SubVector<N,const R>& x) const { return Column(*this)+=x; }
00839     Column operator-(const SubVector<N,const R>& x) const { return Column(*this)-=x; }
00840     Column operator+(const SubMatrix<N,1,R>& x) const { return Column(*this)+=x; }
00841     Column operator-(const SubMatrix<N,1,R>& x) const { return Column(*this)-=x; }
00842     Column operator+(const SubMatrix<N,1,const R>& x) const { return Column(*this)+=x; }
00843     Column operator-(const SubMatrix<N,1,const R>& x) const { return Column(*this)-=x; }
00844     Column operator+(const Matrix<N,1,R>& x) const { return Column(*this)+=x; }
00845     Column operator-(const Matrix<N,1,R>& x) const { return Column(*this)-=x; }
00846     
00847     bool operator==(const SubVector<N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
00848     bool operator!=(const SubVector<N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
00849     bool operator<(const SubVector<N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
00850     bool operator==(const SubVector<N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
00851     bool operator!=(const SubVector<N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
00852     bool operator<(const SubVector<N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
00853     bool operator==(const SubMatrix<N,1,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[0][i]) return false; } return true; }
00854     bool operator!=(const SubMatrix<N,1,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[0][i]) return true; } return false; }
00855     bool operator<(const SubMatrix<N,1,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.cols[0][i]) return true; if(x.cols[0][i]<data[i]) return false; } return false; }
00856     bool operator==(const SubMatrix<N,1,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[0][i]) return false; } return true; }
00857     bool operator!=(const SubMatrix<N,1,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[0][i]) return true; } return false; }
00858     bool operator<(const SubMatrix<N,1,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.cols[0][i]) return true; if(x.cols[0][i]<data[i]) return false; } return false; }
00859     bool operator==(const Matrix<N,1,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
00860     bool operator!=(const Matrix<N,1,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
00861     bool operator<(const Matrix<N,1,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
00862 
00863     //! returns true if all elements are less than the corresponding element
00864     template<typename T> bool operator<<(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; if(x.data[i] <= data[i]) return false; } return true; }
00865     template<typename T> bool operator<<(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; if(x.data[i] <= data[i]) return false; } return true; }
00866     
00867     inline R& operator[](size_t i) { return data[i]; }
00868     inline const R& operator[](size_t i) const { return data[i]; }
00869     
00870     R norm() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { const R x=data[--i]; ans+=x*x; } return std::sqrt(ans); }
00871     R sum() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { ans+=data[--i]; } return ans; }
00872     R sumSq() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { const R x=data[--i]; ans+=x*x; } return ans; }
00873     void abs() { size_t i=N; while(i!=0) { --i; data[i]=std::abs(data[i]); } }
00874     R max() const ATTR_must_check { if(N==0) return R(); R ans=data[N-1]; size_t i=N-1; while(i--!=0) if(ans<data[i]) ans=data[i]; return ans; }
00875     R min() const ATTR_must_check { if(N==0) return R(); R ans=data[N-1]; size_t i=N-1; while(i--!=0) if(ans>data[i]) ans=data[i]; return ans; }
00876     template<typename F> void apply(const F& f) { size_t i=N; while(i--!=0) data[i]=f(data[i]); }
00877     template<typename F> Column<N,R> map(const F& f) const { Column<N,R> ans; size_t i=N; while(i--!=0) ans.data[i]=f(data[i]); return ans; }
00878     
00879     template<typename T> void minimize(const Matrix<N,1,T>& x) { size_t i=N; while(i!=0) { --i; if(x.data[i] < data[i]) data[i]=x.data[i]; } }
00880     template<typename T> void minimize(const SubVector<N,T>& x) { size_t i=N; while(i!=0) { --i; if(x.data[i] < data[i]) data[i]=x.data[i]; } }
00881     template<typename T> void maximize(const Matrix<N,1,T>& x) { size_t i=N; while(i!=0) { --i; if(data[i] < x.data[i]) data[i]=x.data[i]; } }
00882     template<typename T> void maximize(const SubVector<N,T>& x) { size_t i=N; while(i!=0) { --i; if(data[i] < x.data[i]) data[i]=x.data[i]; } }
00883     
00884     inline Row<N,R> transpose() const ATTR_must_check {
00885       Row<N,R> ans=fmat_internal::NoInit();
00886       fmat_internal::tmemcpy<R>(ans.data,data,N);
00887       return ans;
00888     }
00889 
00890     inline std::string fmt(std::string const &numberFormat=defaultNumberFormat, 
00891       std::string const &firstLineStart="[",
00892       std::string const &nextLineStart="",
00893       std::string const &lastLineEnd="]\u1D40", // aka UTF-8 literal 'ᵀ'
00894       std::string const &rowBegin="",
00895       std::string const &elementSep="",
00896       std::string const &rowEnd="",
00897       std::string const &rowSep=" ") const
00898     {
00899       return fullfmt(&data[0],N,1,numberFormat,firstLineStart,nextLineStart,lastLineEnd,rowBegin,elementSep,rowEnd,rowSep);
00900     }
00901 
00902   protected:
00903     using Matrix<N,1,R>::data;
00904   };
00905   // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00906 #if !defined(__clang__) && defined(__GNUC__) && !(__GNUC__==4 && __GNUC_MINOR__<1)
00907   template<size_t N, typename R> const size_t Column<N,R>::HEIGHT=N;
00908   template<size_t N, typename R> const size_t Column<N,R>::WIDTH=1;
00909   template<size_t N, typename R> const size_t Column<N,R>::CAP=N;
00910 #endif
00911   
00912   
00913   template<size_t N, typename R=fmatReal>
00914   class Row : public Matrix<1,N,R> {
00915     template<size_t S, typename T> friend class SubVector;
00916     template<size_t S, typename T> friend class Column;
00917     template<size_t S, typename T> friend class Row;
00918   public:
00919     static const size_t HEIGHT=1;
00920     static const size_t WIDTH=N;
00921     static const size_t CAP=N;
00922     typedef R storage_t;
00923     typedef typename fmat_internal::unconst<R>::type out_t;
00924     
00925     Row(const fmat_internal::NoInit& noinit) : Matrix<1,N,R>(noinit) {}
00926     
00927     Row() : Matrix<1,N,R>() {}
00928     explicit Row(const R x) : Matrix<1,N,R>(x) {}
00929     explicit Row(const R* x, size_t stride=sizeof(R)) : Matrix<1,N,R>(fmat_internal::NoInit()) { size_t i=N; while(i!=0) { --i; data[i]=x[i*stride/sizeof(R)]; } }
00930     Row(const SubVector<N,R>& x) : Matrix<1,N,R>(x.data) {}
00931     Row(const SubVector<N,const R>& x) : Matrix<1,N,R>(x.data) {}
00932     Row(const SubMatrix<1,N,R>& x) : Matrix<1,N,R>(x) {}
00933     Row(const SubMatrix<1,N,const R>& x) : Matrix<1,N,R>(x) {}
00934     Row(const Matrix<1,N,R>& x) : Matrix<1,N,R>(x) {}
00935     template<size_t S> explicit Row(const Row<S,R>& x, size_t srcOffset=0) : Matrix<1,N,R>() {
00936       size_t toCopy = std::min(N,S-srcOffset);
00937       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00938     }
00939     template<size_t S> explicit Row(const SubVector<S,R>& x, size_t srcOffset=0) : Matrix<1,N,R>() {
00940       size_t toCopy = std::min(N,S-srcOffset);
00941       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00942     }
00943     template<size_t S> explicit Row(const SubVector<S,const R>& x, size_t srcOffset=0) : Matrix<1,N,R>() {
00944       size_t toCopy = std::min(N,S-srcOffset);
00945       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00946     }
00947     template<typename T> Row& importFrom(const T& x) { size_t i=N; while(i!=0) { --i; data[i]=x[i]; } return *this; }
00948     template<typename T> T exportTo() const { T x; size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00949     template<typename T> T& exportTo(T& x) const { size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00950     // provided by implicit SubVector constructors
00951     //operator SubVector<N,R>() { return SubVector<N,R>(data); }
00952     //operator SubVector<N,const R>() const { return SubVector<N,const R>(data); }
00953     
00954     Row& operator=(const R* x) { fmat_internal::tmemcpy<R>(data,x,CAP); return *this; }
00955     Row& operator=(R x) { fmat_internal::tmemset<R>(data,x,CAP); return *this; }
00956     Row& operator=(const SubVector<N,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00957     Row& operator=(const SubVector<N,const R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00958     Row& operator=(const SubMatrix<1,N,R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00959     Row& operator=(const SubMatrix<1,N,const R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00960     Row& operator=(const Matrix<1,N,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,CAP); return *this; }
00961     
00962     Row& operator+=(R x) { size_t i=N; while(i!=0) data[--i]+=x; return *this; }
00963     Row& operator-=(R x) { size_t i=N; while(i!=0) data[--i]-=x; return *this; }
00964     Row& operator*=(R x) { size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00965     Row& operator/=(R x) { x=1/x; size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00966     Row<N,out_t> operator+(R x) const { return Row<N,R>(*this)+=x; }
00967     Row<N,out_t> operator-(R x) const { return Row<N,R>(*this)-=x; }
00968     Row<N,out_t> operator*(R x) const { return Row<N,R>(*this)*=x; }
00969     Row<N,out_t> operator/(R x) const { return Row<N,R>(*this)/=x; }
00970     Row<N,out_t> operator-() const { Row<N,R> ans(*this); size_t i=N; while(i--!=0) ans.data[i]=-ans.data[i]; return ans; }
00971     
00972     friend Row<N,out_t> operator+(R x, const Row& a) { return a+x; }
00973     friend Row<N,out_t> operator-(R x, const Row& a) { return (-a)+x; }
00974     friend Row<N,out_t> operator*(R x, const Row& a) { return a*x; }
00975     
00976     Row& operator+=(const SubVector<N,R>& x) { size_t i=CAP; while(i--!=0) data[i]+=x.data[i]; return *this; }
00977     Row& operator-=(const SubVector<N,R>& x) { size_t i=CAP; while(i--!=0) data[i]-=x.data[i]; return *this; }
00978     Row& operator+=(const SubVector<N,const R>& x) { size_t i=CAP; while(i--!=0) data[i]+=x.data[i]; return *this; }
00979     Row& operator-=(const SubVector<N,const R>& x) { size_t i=CAP; while(i--!=0) data[i]-=x.data[i]; return *this; }
00980     Row& operator+=(const SubMatrix<1,N,R>& x) { Matrix<1,N,R>::operator+=(x); return *this;}
00981     Row& operator-=(const SubMatrix<1,N,R>& x) { Matrix<1,N,R>::operator-=(x); return *this;}
00982     Row& operator+=(const SubMatrix<1,N,const R>& x) { Matrix<1,N,R>::operator+=(x); return *this;}
00983     Row& operator-=(const SubMatrix<1,N,const R>& x) { Matrix<1,N,R>::operator-=(x); return *this;}
00984     Row& operator+=(const Matrix<1,N,R>& x) { Matrix<1,N,R>::operator+=(x); return *this;}
00985     Row& operator-=(const Matrix<1,N,R>& x) { Matrix<1,N,R>::operator-=(x); return *this;}
00986     
00987     Row operator+(const SubVector<N,R>& x) const { return Row(*this)+=x; }
00988     Row operator-(const SubVector<N,R>& x) const { return Row(*this)-=x; }
00989     Row operator+(const SubVector<N,const R>& x) const { return Row(*this)+=x; }
00990     Row operator-(const SubVector<N,const R>& x) const { return Row(*this)-=x; }
00991     Row operator+(const SubMatrix<1,N,R>& x) const { return Row(*this)+=x; }
00992     Row operator-(const SubMatrix<1,N,R>& x) const { return Row(*this)-=x; }
00993     Row operator+(const SubMatrix<1,N,const R>& x) const { return Row(*this)+=x; }
00994     Row operator-(const SubMatrix<1,N,const R>& x) const { return Row(*this)-=x; }
00995     Row operator+(const Matrix<1,N,R>& x) const { return Row(*this)+=x; }
00996     Row operator-(const Matrix<1,N,R>& x) const { return Row(*this)-=x; }
00997     
00998     bool operator==(const SubVector<N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
00999     bool operator!=(const SubVector<N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
01000     bool operator<(const SubVector<N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
01001     bool operator==(const SubVector<N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
01002     bool operator!=(const SubVector<N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
01003     bool operator<(const SubVector<N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
01004     bool operator==(const SubMatrix<1,N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[i][0]) return false; } return true; }
01005     bool operator!=(const SubMatrix<1,N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[i][0]) return true; } return false; }
01006     bool operator<(const SubMatrix<1,N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.cols[i][0]) return true; if(x.cols[i][0]<data[i]) return false; } return false; }
01007     bool operator==(const SubMatrix<1,N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[i][0]) return false; } return true; }
01008     bool operator!=(const SubMatrix<1,N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.cols[i][0]) return true; } return false; }
01009     bool operator<(const SubMatrix<1,N,const R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.cols[i][0]) return true; if(x.cols[i][0]<data[i]) return false; } return false; }
01010     bool operator==(const Matrix<1,N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return false; } return true; }
01011     bool operator!=(const Matrix<1,N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]!=x.data[i]) return true; } return false; }
01012     bool operator<(const Matrix<1,N,R>& x) const { size_t i=N; while(i!=0) { --i; if(data[i]<x.data[i]) return true; if(x.data[i]<data[i]) return false; } return false; }
01013     
01014     //! returns true if all elements are less than the corresponding element
01015     template<typename T> bool operator<<(const Matrix<N,1,T>& x) const { size_t i=N; while(i!=0) { --i; if(x.data[i] <= data[i]) return false; } return true; }
01016     template<typename T> bool operator<<(const SubVector<N,T>& x) const { size_t i=N; while(i!=0) { --i; if(x.data[i] <= data[i]) return false; } return true; }
01017     
01018     inline R& operator[](size_t i) { return data[i]; }
01019     inline const R& operator[](size_t i) const { return data[i]; }
01020     
01021     R norm() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { const R x=data[--i]; ans+=x*x; } return std::sqrt(ans); }
01022     R sum() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { ans+=data[--i]; } return ans; }
01023     R sumSq() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { const R x=data[--i]; ans+=x*x; } return ans; }
01024     void abs() { size_t i=N; while(i!=0) { --i; data[i]=std::abs(data[i]); } }
01025     R max() const ATTR_must_check { if(N==0) return R(); R ans=data[N-1]; size_t i=N-1; while(i--!=0) if(ans<data[i]) ans=data[i]; return ans; }
01026     R min() const ATTR_must_check { if(N==0) return R(); R ans=data[N-1]; size_t i=N-1; while(i--!=0) if(ans>data[i]) ans=data[i]; return ans; }
01027     template<typename F> void apply(const F& f) { size_t i=N; while(i--!=0) data[i]=f(data[i]); }
01028     template<typename F> Row<N,R> map(const F& f) const { Row<N,R> ans; size_t i=N; while(i--!=0) ans.data[i]=f(data[i]); return ans; }
01029     
01030     template<typename T> void minimize(const Matrix<1,N,T>& x) { size_t i=N; while(i!=0) { --i; if(x.data[i] < data[i]) data[i]=x.data[i]; } }
01031     template<typename T> void minimize(const SubVector<N,T>& x) { size_t i=N; while(i!=0) { --i; if(x.data[i] < data[i]) data[i]=x.data[i]; } }
01032     template<typename T> void maximize(const Matrix<1,N,T>& x) { size_t i=N; while(i!=0) { --i; if(data[i] < x.data[i]) data[i]=x.data[i]; } }
01033     template<typename T> void maximize(const SubVector<N,T>& x) { size_t i=N; while(i!=0) { --i; if(data[i] < x.data[i]) data[i]=x.data[i]; } }
01034     
01035     inline Column<N,R> transpose() const ATTR_must_check {
01036       Column<N,R> ans=fmat_internal::NoInit();
01037       fmat_internal::tmemcpy<R>(ans.data,data,N);
01038       return ans;
01039     }
01040 
01041     inline std::string fmt(std::string const &numberFormat=defaultNumberFormat, 
01042       std::string const &firstLineStart="[",
01043       std::string const &nextLineStart="",
01044       std::string const &lastLineEnd="]",
01045       std::string const &rowBegin="",
01046       std::string const &elementSep=" ",
01047       std::string const &rowEnd="",
01048       std::string const &rowSep="") const
01049     {
01050       return fullfmt(&data[0],1,N,numberFormat,firstLineStart,nextLineStart,lastLineEnd,rowBegin,elementSep,rowEnd,rowSep);
01051     }
01052 
01053   protected:
01054     using Matrix<1,N,R>::data;
01055   };
01056   
01057   
01058   extern const Column<2> ZERO2; //!< a length 2 column vector with all zeros (could also just use Column<2>(), but this is more semantic)
01059   extern const Column<3> ZERO3; //!< a length 3 column vector with all zeros (could also just use Column<3>(), but this is more semantic)
01060   extern const Column<4> ZEROH; //!< a length 4 column vector representing zero in homogenous coordinates (0,0,0,1)
01061   
01062   extern const Column<2> UNIT2_X; //!< a length 2 column with '1' in the first dimension
01063   extern const Column<2> UNIT2_Y; //!< a length 2 column with '1' in the second dimension
01064   
01065   extern const Column<3> UNIT3_X; //!< a length 3 column with '1' in the first dimension
01066   extern const Column<3> UNIT3_Y; //!< a length 3 column with '1' in the second dimension
01067   extern const Column<3> UNIT3_Z; //!< a length 3 column with '1' in the third dimension
01068   
01069   //! generic packing of N values into a Column<N> (note assumes fmatReal, see packT()
01070   inline Column<2> pack(fmatReal x, fmatReal y) { Column<2> v=fmat_internal::NoInit(); v.data[0]=x; v.data[1]=y; return v; }
01071   inline Column<3> pack(fmatReal x, fmatReal y, fmatReal z) { Column<3> v=fmat_internal::NoInit(); v.data[0]=x; v.data[1]=y; v.data[2]=z; return v; }
01072   inline Column<4> pack(fmatReal x, fmatReal y, fmatReal z, fmatReal d) { Column<4> v=fmat_internal::NoInit(); v.data[0]=x; v.data[1]=y; v.data[2]=z; v.data[3]=d; return v; }
01073   
01074   // alternative implementation, tail recursion faster?
01075   /*template<typename R> Column<2,R> pack(R x, R y) { R data[] = {x,y}; return Column<2,R>(data); }
01076   template<typename R> Column<3,R> pack(R x, R y, R z) { R data[] = {x,y,z}; return Column<3,R>(data); }
01077   template<typename R> Column<4,R> pack(R x, R y, R z, R d) { R data[] = {x,y,z,d}; return Column<4,R>(data); }*/
01078   
01079   //! templated version to pack non fmatReal type, using a different name 'packT' so it needs to be explicitly called, e.g. pack(0,0,1) is generally intended as fmatReal, not int
01080   template<typename R> inline Column<2,R> packT(R x, R y) { Column<2,R> v=fmat_internal::NoInit(); v.data[0]=x; v.data[1]=y; return v; }
01081   template<typename R> inline Column<3,R> packT(R x, R y, R z) { Column<3,R> v=fmat_internal::NoInit(); v.data[0]=x; v.data[1]=y; v.data[2]=z; return v; }
01082   template<typename R> inline Column<4,R> packT(R x, R y, R z, R d) { Column<4,R> v=fmat_internal::NoInit(); v.data[0]=x; v.data[1]=y; v.data[2]=z; v.data[3]=d; return v; }
01083   
01084   //! packing columns: appending an element or concatenating two columns
01085   template<template<size_t N, typename R> class T, size_t N, typename R1, typename R2>
01086   Column<N+1,typename fmat_internal::unconst<R1>::type>
01087   pack(const T<N,R1>& x, R2 y) {
01088     Column<N+1,typename fmat_internal::unconst<R1>::type> data(x); data[N]=y; return data;
01089   }
01090   template<template<size_t N, typename R> class T, size_t N, typename R1, typename R2>
01091   Column<N+1,typename fmat_internal::unconst<R2>::type>
01092   pack(R1 x, const T<N,R2>& y) {
01093     Column<N+1,typename fmat_internal::unconst<R2>::type> data=fmat_internal::NoInit(); data[0]=x; SubVector<N>(data,1)=y; return data;
01094   }
01095   template<template<size_t N, typename R> class T1, template<size_t N, typename R> class T2, size_t N1, size_t N2, typename R1, typename R2>
01096   Column<N1+N2,typename fmat_internal::promotion_trait<R1,R2>::type>
01097   pack(const T1<N1,R1>& x, const T2<N2,R2>& y) {
01098     Column<N1+N2,typename fmat_internal::promotion_trait<R1,R2>::type> data(x); SubVector<N2>(data,N1)=y; return data;
01099   }
01100   
01101   // this is just to pick up subclasses
01102   template<size_t N, typename R1, typename R2>
01103   Column<N+1,typename fmat_internal::unconst<R1>::type> pack(const Column<N,R1>& x, R2 y) {
01104     Column<N+1,typename fmat_internal::unconst<R1>::type> data(x); data[N]=y; return data;
01105   }
01106   template<size_t N, typename R1, typename R2>
01107   Column<N+1,typename fmat_internal::unconst<R2>::type> pack(R1 x, const Column<N,R2>& y) {
01108     Column<N+1,typename fmat_internal::unconst<R2>::type> data=fmat_internal::NoInit(); data[0]=x; SubVector<N,R2>(data,1)=y; return data;
01109   }
01110   template<size_t N1, size_t N2, typename R>
01111   Column<N1+N2,typename fmat_internal::unconst<R>::type> pack(const Column<N1,R>& x, const Column<N2,R>& y) {
01112     Column<N1+N2,typename fmat_internal::unconst<R>::type> data(x); SubVector<N2>(data,N1)=y; return data;
01113   }
01114 
01115   // override: packing a row should return a row
01116   template<size_t N, typename R1, typename R2>
01117   Row<N+1,typename fmat_internal::unconst<R1>::type> pack(const Row<N,R1>& x, R2 y) {
01118     Row<N+1,typename fmat_internal::unconst<R1>::type> data(x); data[N]=y; return data;
01119   }
01120   template<size_t N, typename R1, typename R2>
01121   Row<N+1,typename fmat_internal::unconst<R2>::type> pack(R1 x, const Row<N,R2>& y) {
01122     Row<N+1,typename fmat_internal::unconst<R2>::type> data=fmat_internal::NoInit(); data[0]=x; SubVector<N,R2>(data,1)=y; return data;
01123   }
01124   template<size_t N1, size_t N2, typename R>
01125   Row<N1+N2,typename fmat_internal::unconst<R>::type> pack(const Row<N1,R>& x, const Row<N2,R>& y) {
01126     Row<N1+N2,typename fmat_internal::unconst<R>::type> data(x); SubVector<N2>(data,N1)=y; return data;
01127   }
01128   
01129   
01130   template<size_t N, typename R> inline std::ostream& operator<<(std::ostream& os, const SubVector<N,R>& x) {
01131     return os << x.fmt(); }
01132 
01133   template<size_t H, size_t W, typename R> inline std::ostream& operator<<(std::ostream& os, const SubMatrix<H,W,R>& x) {
01134     return os << x.fmt(); }
01135 
01136   template<size_t H, size_t W, typename R> inline std::ostream& operator<<(std::ostream& os, const Matrix<H,W,R>& x) {
01137     return os << x.fmt(); }
01138 
01139   template<size_t N, typename R> inline std::ostream& operator<<(std::ostream& os, const Column<N,R>& x) {
01140     return os << x.fmt(); }
01141 
01142   template<size_t N, typename R> inline std::ostream& operator<<(std::ostream& os, const Row<N,R>& x) {
01143     return os << x.fmt(); }
01144 
01145 
01146   
01147   template<template<size_t H, size_t W, typename R> class T1, template<size_t H, size_t W, typename R> class T2, size_t H, size_t N, size_t W, typename R1, typename R2>
01148   inline Matrix<H,W,typename fmat_internal::promotion_trait<R1,R2>::type>
01149   operator*(const T1<H,N,R1>& a, const T2<N,W,R2>& b) {
01150     return fmat_internal::mmops<T1<H,N,R1>,T2<N,W,R2> >::multiply(a,b);
01151   }
01152   
01153   /*template<template<size_t H, size_t W, typename R> class T1, template<size_t H, size_t W, typename R> class T2, size_t D, typename R1, typename R2>
01154   inline Matrix<D,D,typename fmat_internal::promotion_trait<R1,R2>::type>
01155   operator*(const T1<D,D,R1>& a, const T2<D,D,R2>& b) {
01156     return fmat_internal::mmops<T1<D,D,R1>,T2<D,D,R2> >::multiply(a,b);
01157   }*/
01158   
01159   template<template<size_t H, size_t W, typename R> class T1, template<size_t H, size_t W, typename R> class T2, size_t D, typename R1, typename R2>
01160   inline T1<D,D,R1>&
01161   operator*=(T1<D,D,R1>& a, const T2<D,D,R2>& b) {
01162     a=fmat_internal::mmops<T1<D,D,R1>,T2<D,D,R2> >::multiply(a,b);
01163     return a;
01164   }
01165   
01166   template<template<size_t H, size_t W, typename R> class T2, size_t D, typename R1, typename R2>
01167   inline const SubMatrix<D,D,R1>&
01168   operator*=(const SubMatrix<D,D,R1>& a, const T2<D,D,R2>& b) {
01169     a=fmat_internal::mmops<SubMatrix<D,D,R1>,T2<D,D,R2> >::multiply(a,b);
01170     return a;
01171   }
01172   
01173   template<template<size_t H, size_t W, typename R> class T1, template<size_t N, typename R> class T2, size_t H, size_t N, typename R1, typename R2>
01174   inline Column<H,typename fmat_internal::promotion_trait<R1,R2>::type>
01175   operator*(const T1<H,N,R1>& a, const T2<N,R2>& b) {
01176     return fmat_internal::mvops<T1<H,N,R1>,T2<N,R2> >::multiply(a,b);
01177   }
01178   
01179   template<template<size_t W, typename R> class T1, template<size_t H, size_t W, typename R> class T2, size_t N, size_t W, typename R1, typename R2>
01180   inline Row<W,typename fmat_internal::promotion_trait<R1,R2>::type>
01181   operator*(const T1<N,R1>& a, const T2<N,W,R2>& b) {
01182     return fmat_internal::mvops<T2<N,W,R2>,T1<N,R1> >::multiply(a,b);
01183   }
01184   
01185   template<template<size_t N, typename R> class T, size_t N, typename R>
01186   inline fmat::Column<N,typename fmat_internal::unconst<R>::type>
01187   abs(const T<N,R>& v) {
01188     fmat::Column<N,typename fmat_internal::unconst<R>::type> ans=fmat_internal::NoInit();
01189     for(size_t i=N; i!=0; ) {
01190       --i;
01191       ans[i]=std::abs(v[i]);
01192     }
01193     return ans;
01194   }
01195 
01196   template<template<size_t H, size_t W, typename R> class T, size_t H, size_t W, typename R>
01197   inline fmat::Matrix<H,W,typename fmat_internal::unconst<R>::type>
01198   abs(const T<H,W,R>& m) {
01199     typedef typename fmat_internal::unconst<R>::type out_t;
01200     fmat::Matrix<H,W,out_t> ans=fmat_internal::NoInit();
01201     out_t* ad=&ans(0,0);
01202     const R* md=&m(0,0);
01203     for(size_t i=H*W; i!=0; ) {
01204       --i;
01205       ad[i]=std::abs(md[i]);
01206     }
01207     return ans;
01208   }
01209   
01210   template<typename R> inline R atan(const Column<2,R>& v) { return std::atan2(v[1],v[0]); }
01211   template<typename R> inline R atan(const Row<2,R>& v) { return std::atan2(v[1],v[0]); }
01212   template<typename R> inline R atan(const SubVector<2,R>& v) { return std::atan2(v[1],v[0]); }
01213   
01214   template<template<size_t N, typename R> class T1, template<size_t N, typename R> class T2, size_t N, typename R1, typename R2>
01215   typename fmat_internal::promotion_trait<R1,R2>::type
01216   dotProduct(const T1<N,R1>& a, const T2<N,R2>& b) {
01217     typename fmat_internal::promotion_trait<R1,R2>::type ans=0;
01218     size_t i=N;
01219     while(i--!=0)
01220       ans+=a[i]*b[i];
01221     return ans; 
01222   }
01223   // this version of dotProduct() gets picked up when using subclasses, which don't match the template forms above
01224   template<class Ta, class Tb>
01225   inline typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type
01226   dotProduct(const Ta& a, const Tb& b) {
01227     (void)sizeof(fmat_internal::CompileTimeAssert<Length_mismatch_or_non_vector,Ta::CAP==Tb::CAP && Ta::HEIGHT==Ta::CAP && Tb::HEIGHT==Tb::CAP>);
01228     typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type ans=0;
01229     size_t i=Ta::CAP;
01230     while(i--!=0)
01231       ans+=a[i]*b[i];
01232     return ans; 
01233   }
01234   
01235   template<class Ta, class Tb>
01236   inline Column<3,typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type>
01237   crossProduct(const Ta& a, const Tb& b) {
01238     return packT<typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type>(
01239       a[1] * b[2] - a[2] * b[1],
01240       a[2] * b[0] - a[0] * b[2],
01241       a[0] * b[1] - a[1] * b[0]
01242     );
01243   }
01244   
01245   template<template<size_t H, size_t W, typename R> class M, typename R>
01246   typename fmat_internal::unconst<R>::type
01247   determinant(const M<2,2,R>& m) {
01248     return m(0,0) * m(1,1) - m(0,1) * m(1,0);
01249   }
01250   
01251   template<template<size_t H, size_t W, typename R> class M, typename R>
01252   typename fmat_internal::unconst<R>::type
01253   determinant(const M<3,3,R>& m) {
01254     return m(0,0) * m(1,1) * m(2,2) + m(0,1) * m(1,2) * m(2,0) + m(0,2) * m(1,0) * m(2,1)
01255     - m(0,0) * m(1,2) * m(2,1) - m(0,1) * m(1,0) * m(2,2) - m(0,2) * m(1,1) * m(2,0);
01256   }
01257   
01258   //! Computes and returns the inverse of a square matrix using Gauss-Jordan elimination
01259   /*! The computation is done with column-wise operations for computational efficiency.
01260    *  You can think of this as doing the inverse in transposed space: (mᵀ)⁻¹ == (m⁻¹)ᵀ */
01261   template<typename M>
01262   Matrix<M::HEIGHT,M::WIDTH,typename fmat_internal::unconst<typename M::storage_t>::type >
01263   invert(const M& m) {
01264     (void)sizeof(fmat_internal::CompileTimeAssert<NonSquare_Matrix,M::WIDTH==M::HEIGHT>);
01265     typedef typename fmat_internal::unconst<typename M::storage_t>::type R;
01266     const size_t DIM=M::HEIGHT;
01267     
01268     Matrix<DIM*2,DIM,R> x(m);
01269     for(unsigned int c=0; c<DIM; ++c)
01270       x(DIM+c,c)=1;
01271     
01272     for(unsigned int c=0; c<DIM; ++c) {
01273       // find pivot
01274       R mx=std::abs(x(c,c));
01275       unsigned int mxi=c;
01276       for(unsigned int r=c+1; r<DIM; ++r) {
01277         const R v=std::abs(x(c,r));
01278         if(v>mx) {
01279           mx=v;
01280           mxi=r;
01281         }
01282       }
01283       if(mx<std::numeric_limits<float>::epsilon())
01284         throw std::underflow_error("low rank matrix, non-invertable");
01285       
01286       // swap to put pivot in position
01287       Column<DIM*2,R> tmp = x.column(c);
01288       x.column(c) = x.column(mxi);
01289       x.column(mxi) = tmp;
01290       
01291       {
01292         const R p=x(c,c);
01293         for(unsigned int c2=c+1; c2<DIM*2; ++c2)
01294           x(c2,c)/=p;
01295         x(c,c)=1;
01296       }
01297       
01298       for(unsigned int r=c+1; r<DIM; ++r) {
01299         const R p = x(c,r);
01300         for(unsigned int c2=c+1; c2<DIM*2; ++c2)
01301           x(c2,r)-=x(c2,c)*p;
01302         x(c,r)=0;
01303       }
01304     }
01305     for(unsigned int c=0; c<DIM; ++c) {
01306       for(unsigned int r=0; r<c; ++r) {
01307         const R p = x(c,r);
01308         for(unsigned int c2=c+1; c2<DIM*2; ++c2)
01309           x(c2,r)-=x(c2,c)*p;
01310         x(c,r)=0;
01311       }
01312     }
01313     return SubMatrix<DIM,DIM,R>(x,DIM,0);
01314   }
01315   
01316   //! returns the determinant for 2x2 matrices
01317   template<template<size_t H, size_t W, typename R> class T, typename R>
01318   inline R det(const T<2,2,R>& m) {
01319     return m(0,0)*m(1,1) - m(1,0)*m(0,1);
01320   }
01321   
01322   //! returns the determinant for 3x3 matrices
01323   template<template<size_t H, size_t W, typename R> class T, typename R>
01324   inline R det(const T<3,3,R>& m) {
01325     const R cofactor0 = m(1,1)*m(2,2) - m(1,2)*m(2,1);
01326     const R cofactor1 = m(1,2)*m(2,0) - m(1,0)*m(2,2);
01327     const R cofactor2 = m(1,0)*m(2,1) - m(1,1)*m(2,0);
01328         return m(0,0)*cofactor0 + m(0,1)*cofactor1 + m(0,2)*cofactor2;
01329   }
01330   // todo: det() for higher dimensions
01331   
01332   
01333   // Performance specializations:
01334   template<template<size_t N, typename R> class V1, template<size_t N, typename R> class V2, typename R1, typename R2>
01335   inline typename fmat_internal::promotion_trait<R1,R2>::type dotProduct(const V1<2,R1>& a, const V2<2,R2>& b) { return a[0]*b[0] + a[1]*b[1]; }
01336   template<template<size_t N, typename R> class V1, template<size_t N, typename R> class V2, typename R1, typename R2>
01337   inline typename fmat_internal::promotion_trait<R1,R2>::type dotProduct(const V1<3,R1>& a, const V2<3,R2>& b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
01338   template<template<size_t N, typename R> class V1, template<size_t N, typename R> class V2, typename R1, typename R2>
01339   inline typename fmat_internal::promotion_trait<R1,R2>::type dotProduct(const V1<4,R1>& a, const V2<4,R2>& b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]; }
01340   
01341   namespace fmat_internal {
01342     inline float hypot(float a, float b) ATTR_pure ATTR_always_inline;
01343     inline float hypot(float a, float b) { return ::hypotf(a,b); }
01344     inline double hypot(double a, double b) ATTR_pure ATTR_always_inline;
01345     inline double hypot(double a, double b) { return ::hypot(a,b); }
01346 #ifndef PLATFORM_APERIOS
01347     inline long double hypot(long double a, long double b) ATTR_pure ATTR_always_inline;
01348     inline long double hypot(long double a, long double b) { return ::hypotl(a,b); }
01349 #endif
01350     template<class T> T hypot(T a, T b) { return std::sqrt(a*a,b*b); }
01351   }
01352   
01353   template<> inline fmatReal Column<2,fmatReal>::norm() const { return fmat_internal::hypot(data[0],data[1]); }
01354   template<> inline fmatReal Column<3,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01355   template<> inline fmatReal Column<4,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01356   template<> inline fmatReal SubVector<2,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1]); }
01357   template<> inline fmatReal SubVector<3,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01358   template<> inline fmatReal SubVector<4,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01359   template<> inline fmatReal SubVector<2,const fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1]); }
01360   template<> inline fmatReal SubVector<3,const fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01361   template<> inline fmatReal SubVector<4,const fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01362   template<> inline fmatReal Row<2,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1]); }
01363   template<> inline fmatReal Row<3,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01364   template<> inline fmatReal Row<4,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01365 
01366   template<> inline fmatReal Column<2,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01367   template<> inline fmatReal Column<3,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01368   template<> inline fmatReal Column<4,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01369   template<> inline fmatReal SubVector<2,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01370   template<> inline fmatReal SubVector<3,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01371   template<> inline fmatReal SubVector<4,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01372   template<> inline fmatReal SubVector<2,const fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01373   template<> inline fmatReal SubVector<3,const fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01374   template<> inline fmatReal SubVector<4,const fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01375   template<> inline fmatReal Row<2,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01376   template<> inline fmatReal Row<3,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01377   template<> inline fmatReal Row<4,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2] + data[3]*data[3]); }
01378   
01379 
01380   template<> inline Column<2,fmatReal>& Column<2,fmatReal>::operator+=(const SubVector<2,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; return *this; }
01381   template<> inline Column<3,fmatReal>& Column<3,fmatReal>::operator+=(const SubVector<3,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; data[2]+=x.data[2]; return *this; }
01382   template<> inline Column<4,fmatReal>& Column<4,fmatReal>::operator+=(const SubVector<4,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; data[2]+=x.data[2]; data[3]+=x.data[3]; return *this; }
01383   template<> inline Matrix<2,1,fmatReal>& Matrix<2,1,fmatReal>::operator+=(const Matrix<2,1,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; return *this; }
01384   template<> inline Matrix<3,1,fmatReal>& Matrix<3,1,fmatReal>::operator+=(const Matrix<3,1,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; data[2]+=x.data[2]; return *this; }
01385   template<> inline Matrix<4,1,fmatReal>& Matrix<4,1,fmatReal>::operator+=(const Matrix<4,1,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; data[2]+=x.data[2]; data[3]+=x.data[3]; return *this; }
01386   template<> inline Row<2,fmatReal>& Row<2,fmatReal>::operator+=(const SubVector<2,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; return *this; }
01387   template<> inline Row<3,fmatReal>& Row<3,fmatReal>::operator+=(const SubVector<3,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; data[2]+=x.data[2]; return *this; }
01388   template<> inline Row<4,fmatReal>& Row<4,fmatReal>::operator+=(const SubVector<4,fmatReal>& x) { data[0]+=x.data[0]; data[1]+=x.data[1]; data[2]+=x.data[2]; data[3]+=x.data[3]; return *this; }
01389 
01390   template<> inline Column<2,fmatReal>& Column<2,fmatReal>::operator-=(const SubVector<2,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; return *this; }
01391   template<> inline Column<3,fmatReal>& Column<3,fmatReal>::operator-=(const SubVector<3,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; data[2]-=x.data[2]; return *this; }
01392   template<> inline Column<4,fmatReal>& Column<4,fmatReal>::operator-=(const SubVector<4,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; data[2]-=x.data[2]; data[3]-=x.data[3]; return *this; }
01393   template<> inline Matrix<2,1,fmatReal>& Matrix<2,1,fmatReal>::operator-=(const Matrix<2,1,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; return *this; }
01394   template<> inline Matrix<3,1,fmatReal>& Matrix<3,1,fmatReal>::operator-=(const Matrix<3,1,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; data[2]-=x.data[2]; return *this; }
01395   template<> inline Matrix<4,1,fmatReal>& Matrix<4,1,fmatReal>::operator-=(const Matrix<4,1,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; data[2]-=x.data[2]; data[3]-=x.data[3]; return *this; }
01396   template<> inline Row<2,fmatReal>& Row<2,fmatReal>::operator-=(const SubVector<2,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; return *this; }
01397   template<> inline Row<3,fmatReal>& Row<3,fmatReal>::operator-=(const SubVector<3,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; data[2]-=x.data[2]; return *this; }
01398   template<> inline Row<4,fmatReal>& Row<4,fmatReal>::operator-=(const SubVector<4,fmatReal>& x) { data[0]-=x.data[0]; data[1]-=x.data[1]; data[2]-=x.data[2]; data[3]-=x.data[3]; return *this; }
01399   
01400   template<> inline const SubVector<2,fmatReal>& SubVector<2,fmatReal>::operator*=(fmatReal x) const { data[0]*=x; data[1]*=x; return *this; }
01401   template<> inline const SubVector<3,fmatReal>& SubVector<3,fmatReal>::operator*=(fmatReal x) const { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01402   template<> inline const SubVector<4,fmatReal>& SubVector<4,fmatReal>::operator*=(fmatReal x) const { data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01403   template<> inline Matrix<2,1,fmatReal>& Matrix<2,1,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; return *this; }
01404   template<> inline Matrix<3,1,fmatReal>& Matrix<3,1,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01405   template<> inline Matrix<4,1,fmatReal>& Matrix<4,1,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01406   template<> inline Column<2,fmatReal>& Column<2,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; return *this; }
01407   template<> inline Column<3,fmatReal>& Column<3,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01408   template<> inline Column<4,fmatReal>& Column<4,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01409   template<> inline Row<2,fmatReal>& Row<2,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; return *this; }
01410   template<> inline Row<3,fmatReal>& Row<3,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01411   template<> inline Row<4,fmatReal>& Row<4,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01412 
01413   template<> inline const SubVector<2,fmatReal>& SubVector<2,fmatReal>::operator/=(fmatReal x) const { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01414   template<> inline const SubVector<3,fmatReal>& SubVector<3,fmatReal>::operator/=(fmatReal x) const { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01415   template<> inline const SubVector<4,fmatReal>& SubVector<4,fmatReal>::operator/=(fmatReal x) const { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01416   template<> inline Matrix<2,1,fmatReal>& Matrix<2,1,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01417   template<> inline Matrix<3,1,fmatReal>& Matrix<3,1,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01418   template<> inline Matrix<4,1,fmatReal>& Matrix<4,1,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01419   template<> inline Column<2,fmatReal>& Column<2,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01420   template<> inline Column<3,fmatReal>& Column<3,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01421   template<> inline Column<4,fmatReal>& Column<4,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01422   template<> inline Row<2,fmatReal>& Row<2,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01423   template<> inline Row<3,fmatReal>& Row<3,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01424   template<> inline Row<4,fmatReal>& Row<4,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; data[2]*=x; data[3]*=x; return *this; }
01425 
01426   namespace fmat_internal {
01427     
01428     template<template<size_t H, size_t W, typename R> class T1, template<size_t N, typename R> class T2, typename R1, typename R2>
01429     struct mvops<T1<2,2,R1>,T2<2,R2> > {
01430       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01431       inline static Column<2,R> multiply(const T1<2,2,R1>& ma, const T2<2,R2>& b) {
01432         Column<2,R> ans=fmat_internal::NoInit();
01433         const R1 *a=&ma(0,0);
01434         ans[0] = a[0*2+0]*b[0] + a[1*2+0]*b[1];
01435         ans[1] = a[0*2+1]*b[0] + a[1*2+1]*b[1];
01436         return ans;
01437       }
01438       inline static Row<2,R> multiply(const T2<2,R2>& b, const T1<2,2,R1>& ma) {
01439         Row<2,R> ans=fmat_internal::NoInit();
01440         const R1 *a=&ma(0,0);
01441         ans[0] = a[0*2+0]*b[0] + a[0*2+1]*b[1];
01442         ans[1] = a[1*2+0]*b[0] + a[1*2+1]*b[1];
01443         return ans;
01444       }
01445     };
01446     template<template<size_t H, size_t W, typename R> class T1, template<size_t N, typename R> class T2, typename R1, typename R2>
01447     struct mvops<T1<3,3,R1>,T2<3,R2> > {
01448       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01449       inline static Column<3,R> multiply(const T1<3,3,R1>& ma, const T2<3,R2>& b) {
01450         Column<3,R> ans=fmat_internal::NoInit();
01451         const R *a=&ma(0,0);
01452         ans[0] = a[0*3+0]*b[0] + a[1*3+0]*b[1] + a[2*3+0]*b[2];
01453         ans[1] = a[0*3+1]*b[0] + a[1*3+1]*b[1] + a[2*3+1]*b[2];
01454         ans[2] = a[0*3+2]*b[0] + a[1*3+2]*b[1] + a[2*3+2]*b[2];
01455         return ans;
01456       }
01457       inline static Row<3,R> multiply(const T2<3,R2>& b, const T1<3,3,R1>& ma) {
01458         Row<3,R> ans=fmat_internal::NoInit();
01459         const R *a=&ma(0,0);
01460         ans[0] = a[0*3+0]*b[0] + a[0*3+1]*b[1] + a[0*3+2]*b[2];
01461         ans[1] = a[1*3+0]*b[0] + a[1*3+1]*b[1] + a[1*3+2]*b[2];
01462         ans[2] = a[2*3+0]*b[0] + a[2*3+1]*b[1] + a[2*3+2]*b[2];
01463         return ans;
01464       }
01465     };
01466     template<template<size_t H, size_t W, typename R> class T1, template<size_t N, typename R> class T2, typename R1, typename R2>
01467     struct mvops<T1<4,4,R1>,T2<4,R2> > {
01468       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01469       inline static Column<4,R> multiply(const T1<4,4,R1>& ma, const T2<4,R2>& b) {
01470         Column<4,R> ans=fmat_internal::NoInit();
01471         const R *a=&ma(0,0);
01472         ans[0] = a[0*4+0]*b[0] + a[1*4+0]*b[1] + a[2*4+0]*b[2] + a[3*4+0]*b[3];
01473         ans[1] = a[0*4+1]*b[0] + a[1*4+1]*b[1] + a[2*4+1]*b[2] + a[3*4+1]*b[3];
01474         ans[2] = a[0*4+2]*b[0] + a[1*4+2]*b[1] + a[2*4+2]*b[2] + a[3*4+2]*b[3];
01475         ans[3] = a[0*4+3]*b[0] + a[1*4+3]*b[1] + a[2*4+3]*b[2] + a[3*4+3]*b[3];
01476         return ans;
01477       }
01478       inline static Row<4,R> multiply(const T2<4,R2>& b, const T1<4,4,R1>& ma) {
01479         Row<4,R> ans=fmat_internal::NoInit();
01480         const R *a=&ma(0,0);
01481         ans[0] = a[0*4+0]*b[0] + a[0*4+1]*b[1] + a[0*4+2]*b[2] + a[0*4+3]*b[3];
01482         ans[1] = a[1*4+0]*b[0] + a[1*4+1]*b[1] + a[1*4+2]*b[2] + a[1*4+3]*b[3];
01483         ans[2] = a[2*4+0]*b[0] + a[2*4+1]*b[1] + a[2*4+2]*b[2] + a[2*4+3]*b[3];
01484         ans[3] = a[3*4+0]*b[0] + a[3*4+1]*b[1] + a[3*4+2]*b[2] + a[3*4+3]*b[3];
01485         return ans;
01486       }
01487     };
01488 
01489     template<template<size_t H, size_t W, typename R> class T1, template<size_t H, size_t W, typename R> class T2, typename R1, typename R2>
01490     struct mmops<T1<2,2,R1>,T2<2,2,R2> > {
01491       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01492       inline static Matrix<2,2,R> multiply(const T1<2,2,R1>& ma, const T2<2,2,R2>& mb) {
01493         Matrix<2,2,R> mans=fmat_internal::NoInit();
01494         R *ans=&mans(0,0);
01495         const R1 *a=&ma(0,0);
01496         const R2 *b=&mb(0,0);
01497         ans[0+2*0] = a[0+2*0]*b[0+2*0] + a[0+2*1]*b[1+2*0];
01498         ans[1+2*0] = a[1+2*0]*b[0+2*0] + a[1+2*1]*b[1+2*0];
01499         ans[0+2*1] = a[0+2*0]*b[0+2*1] + a[0+2*1]*b[1+2*1];
01500         ans[1+2*1] = a[1+2*0]*b[0+2*1] + a[1+2*1]*b[1+2*1];
01501         return mans;
01502       }
01503     };
01504     template<template<size_t H, size_t W, typename R> class T1, template<size_t H, size_t W, typename R> class T2, typename R1, typename R2>
01505     struct mmops<T1<3,3,R1>,T2<3,3,R2> > {
01506       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01507       inline static Matrix<3,3,R> multiply(const T1<3,3,R1>& ma, const T2<3,3,R2>& mb) {
01508         Matrix<3,3,R> mans=fmat_internal::NoInit();
01509         R *ans=&mans(0,0);
01510         const R1 *a=&ma(0,0);
01511         const R2 *b=&mb(0,0);
01512         ans[0+3*0] = a[0+3*0]*b[0+3*0] + a[0+3*1]*b[1+3*0] + a[0+3*2]*b[2+3*0];
01513         ans[1+3*0] = a[1+3*0]*b[0+3*0] + a[1+3*1]*b[1+3*0] + a[1+3*2]*b[2+3*0];
01514         ans[2+3*0] = a[2+3*0]*b[0+3*0] + a[2+3*1]*b[1+3*0] + a[2+3*2]*b[2+3*0];
01515         ans[0+3*1] = a[0+3*0]*b[0+3*1] + a[0+3*1]*b[1+3*1] + a[0+3*2]*b[2+3*1];
01516         ans[1+3*1] = a[1+3*0]*b[0+3*1] + a[1+3*1]*b[1+3*1] + a[1+3*2]*b[2+3*1];
01517         ans[2+3*1] = a[2+3*0]*b[0+3*1] + a[2+3*1]*b[1+3*1] + a[2+3*2]*b[2+3*1];
01518         ans[0+3*2] = a[0+3*0]*b[0+3*2] + a[0+3*1]*b[1+3*2] + a[0+3*2]*b[2+3*2];
01519         ans[1+3*2] = a[1+3*0]*b[0+3*2] + a[1+3*1]*b[1+3*2] + a[1+3*2]*b[2+3*2];
01520         ans[2+3*2] = a[2+3*0]*b[0+3*2] + a[2+3*1]*b[1+3*2] + a[2+3*2]*b[2+3*2];
01521         return mans;
01522       }
01523     };
01524     template<template<size_t H, size_t W, typename R> class T1, template<size_t H, size_t W, typename R> class T2, typename R1, typename R2>
01525     struct mmops<T1<4,4,R1>,T2<4,4,R2> > {
01526       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01527       inline static Matrix<4,4,R> multiply(const T1<4,4,R1>& ma, const T2<4,4,R2>& mb) {
01528         Matrix<4,4,R> mans=fmat_internal::NoInit();
01529         R *ans=&mans(0,0);
01530         const R1 *a=&ma(0,0);
01531         const R2 *b=&mb(0,0);
01532         ans[0+4*0] = a[0+4*0]*b[0+4*0] + a[0+4*1]*b[1+4*0] + a[0+4*2]*b[2+4*0] + a[0+4*3]*b[3+4*0];
01533         ans[1+4*0] = a[1+4*0]*b[0+4*0] + a[1+4*1]*b[1+4*0] + a[1+4*2]*b[2+4*0] + a[1+4*3]*b[3+4*0];
01534         ans[2+4*0] = a[2+4*0]*b[0+4*0] + a[2+4*1]*b[1+4*0] + a[2+4*2]*b[2+4*0] + a[2+4*3]*b[3+4*0];
01535         ans[3+4*0] = a[3+4*0]*b[0+4*0] + a[3+4*1]*b[1+4*0] + a[3+4*2]*b[2+4*0] + a[3+4*3]*b[3+4*0];
01536         ans[0+4*1] = a[0+4*0]*b[0+4*1] + a[0+4*1]*b[1+4*1] + a[0+4*2]*b[2+4*1] + a[0+4*3]*b[3+4*1];
01537         ans[1+4*1] = a[1+4*0]*b[0+4*1] + a[1+4*1]*b[1+4*1] + a[1+4*2]*b[2+4*1] + a[1+4*3]*b[3+4*1];
01538         ans[2+4*1] = a[2+4*0]*b[0+4*1] + a[2+4*1]*b[1+4*1] + a[2+4*2]*b[2+4*1] + a[2+4*3]*b[3+4*1];
01539         ans[3+4*1] = a[3+4*0]*b[0+4*1] + a[3+4*1]*b[1+4*1] + a[3+4*2]*b[2+4*1] + a[3+4*3]*b[3+4*1];
01540         ans[0+4*2] = a[0+4*0]*b[0+4*2] + a[0+4*1]*b[1+4*2] + a[0+4*2]*b[2+4*2] + a[0+4*3]*b[3+4*2];
01541         ans[1+4*2] = a[1+4*0]*b[0+4*2] + a[1+4*1]*b[1+4*2] + a[1+4*2]*b[2+4*2] + a[1+4*3]*b[3+4*2];
01542         ans[2+4*2] = a[2+4*0]*b[0+4*2] + a[2+4*1]*b[1+4*2] + a[2+4*2]*b[2+4*2] + a[2+4*3]*b[3+4*2];
01543         ans[3+4*2] = a[3+4*0]*b[0+4*2] + a[3+4*1]*b[1+4*2] + a[3+4*2]*b[2+4*2] + a[3+4*3]*b[3+4*2];
01544         ans[0+4*3] = a[0+4*0]*b[0+4*3] + a[0+4*1]*b[1+4*3] + a[0+4*2]*b[2+4*3] + a[0+4*3]*b[3+4*3];
01545         ans[1+4*3] = a[1+4*0]*b[0+4*3] + a[1+4*1]*b[1+4*3] + a[1+4*2]*b[2+4*3] + a[1+4*3]*b[3+4*3];
01546         ans[2+4*3] = a[2+4*0]*b[0+4*3] + a[2+4*1]*b[1+4*3] + a[2+4*2]*b[2+4*3] + a[2+4*3]*b[3+4*3];
01547         ans[3+4*3] = a[3+4*0]*b[0+4*3] + a[3+4*1]*b[1+4*3] + a[3+4*2]*b[2+4*3] + a[3+4*3]*b[3+4*3];
01548         return mans;
01549       }
01550     };
01551   }
01552 
01553   extern template class SubVector<3,fmatReal>;
01554   extern template class Column<3,fmatReal>;
01555   extern template class SubMatrix<3,3,fmatReal>;
01556   extern template class Matrix<3,4,fmatReal>;
01557 
01558 } // namespace
01559 
01560 #endif
01561 
01562 /*! @file
01563  * @brief Defines fmat namespace, for fixed-dimension matrix computation
01564  * @author Ethan Tira-Thompson (ejt) (Creator)
01565  */

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:40 2016 by Doxygen 1.6.3