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 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     struct IdentityMatrix : Matrix {
00732       IdentityMatrix() : Matrix() {
00733         size_t d = std::min(H,W);
00734         for(size_t i=0; i<d; ++i)
00735           this->data[i*H+i]=1;
00736       }
00737     };
00738 
00739   };
00740   // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00741 #if !defined(__clang__) && defined(__GNUC__) && !(__GNUC__==4 && __GNUC_MINOR__<1)
00742   template<size_t H, size_t W, typename R> const size_t Matrix<H,W,R>::HEIGHT=H;
00743   template<size_t H, size_t W, typename R> const size_t Matrix<H,W,R>::WIDTH=W;
00744   template<size_t H, size_t W, typename R> const size_t Matrix<H,W,R>::CAP=H*W;
00745 #endif
00746   
00747   
00748   template<size_t N, typename R=fmatReal>
00749   class Column : public Matrix<N,1,R> {
00750     template<size_t S, typename T> friend class SubVector;
00751     template<size_t S, typename T> friend class Column;
00752     template<size_t S, typename T> friend class Row;
00753     friend Column<2,R> packT<>(R x, R y);
00754     friend Column<3,R> packT<>(R x, R y, R z);
00755     friend Column<4,R> packT<>(R x, R y, R z, R d);
00756     friend Column<2,fmatReal> pack(fmatReal x, fmatReal y);
00757     friend Column<3,fmatReal> pack(fmatReal x, fmatReal y, fmatReal z);
00758     friend Column<4,fmatReal> pack(fmatReal x, fmatReal y, fmatReal z, fmatReal d);
00759   public:
00760     // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00761 #if defined(__clang__) || !defined(__GNUC__) || (__GNUC__==4 && __GNUC_MINOR__<1)
00762     static const size_t HEIGHT=N;
00763     static const size_t WIDTH=1;
00764     static const size_t CAP=N;
00765 #else
00766     static const size_t HEIGHT;
00767     static const size_t WIDTH;
00768     static const size_t CAP;
00769 #endif
00770     typedef R storage_t;
00771     typedef typename fmat_internal::unconst<R>::type out_t;
00772     
00773     Column(const fmat_internal::NoInit& noinit) : Matrix<N,1,R>(noinit) {}
00774     
00775     Column() : Matrix<N,1,R>() {}
00776     explicit Column(const R x) : Matrix<N,1,R>(x) {}
00777     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)]; } }
00778     Column(const SubVector<N,R>& x) : Matrix<N,1,R>(x.data) {}
00779     Column(const SubVector<N,const R>& x) : Matrix<N,1,R>(x.data) {}
00780     Column(const SubMatrix<N,1,R>& x) : Matrix<N,1,R>(x) {}
00781     Column(const SubMatrix<N,1,const R>& x) : Matrix<N,1,R>(x) {}
00782     Column(const Matrix<N,1,R>& x) : Matrix<N,1,R>(x) {}
00783     template<size_t S> explicit Column(const Column<S,R>& x, size_t srcOffset=0) : Matrix<N,1,R>() {
00784       size_t toCopy = std::min(N,S-srcOffset);
00785       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00786     }
00787     template<size_t S> explicit Column(const SubVector<S,R>& x, size_t srcOffset=0) : Matrix<N,1,R>() {
00788       size_t toCopy = std::min(N,S-srcOffset);
00789       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00790     }
00791     template<size_t S> explicit Column(const SubVector<S,const R>& x, size_t srcOffset=0) : Matrix<N,1,R>() {
00792       size_t toCopy = std::min(N,S-srcOffset);
00793       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00794     }
00795     template<typename T> Column& importFrom(const T& x) { size_t i=N; while(i!=0) { --i; data[i]=x[i]; } return *this; }
00796     template<typename T> T exportTo() const { T x; size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00797     template<typename T> T& exportTo(T& x) const { size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00798     // provided by implicit SubVector constructors
00799     //operator SubVector<N,R>() { return SubVector<N,R>(data); }
00800     //operator SubVector<N,const R>() const { return SubVector<N,const R>(data); }
00801     
00802     Column& operator=(const R* x) { fmat_internal::tmemcpy<R>(data,x,CAP); return *this; }
00803     Column& operator=(R x) { fmat_internal::tmemset<R>(data,x,CAP); return *this; }
00804     Column& operator=(const SubVector<N,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00805     Column& operator=(const SubVector<N,const R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00806     Column& operator=(const SubMatrix<N,1,R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00807     Column& operator=(const SubMatrix<N,1,const R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00808     Column& operator=(const Matrix<N,1,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,CAP); return *this; }
00809     
00810     Column& operator+=(R x) { size_t i=N; while(i!=0) data[--i]+=x; return *this; }
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) { x=1/x; size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00814     Column<N,out_t> operator+(R x) const { return Column<N,out_t>(*this)+=x; }
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-() const { Column<N,out_t> ans(*this); size_t i=N; while(i--!=0) ans.data[i]=-ans.data[i]; return ans; }
00819     
00820     friend Column<N,out_t> operator+(R x, const Column& a) { return a+x; }
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     
00824     Column& operator+=(const SubVector<N,R>& x) { size_t i=CAP; while(i--!=0) data[i]+=x.data[i]; return *this; }
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,const 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 SubMatrix<N,1,R>& x) { Matrix<N,1,R>::operator+=(x); 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,const 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 Matrix<N,1,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     
00835     Column operator+(const SubVector<N,R>& x) const { return Column(*this)+=x; }
00836     Column operator-(const SubVector<N,R>& x) const { return Column(*this)-=x; }
00837     Column operator+(const SubVector<N,const 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 SubMatrix<N,1,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,const 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 Matrix<N,1,R>& x) const { return Column(*this)+=x; }
00844     Column operator-(const Matrix<N,1,R>& x) const { return Column(*this)-=x; }
00845     
00846     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; }
00847     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; }
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; if(x.data[i]<data[i]) return false; } return false; }
00849     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; }
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 true; } return false; }
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; if(x.data[i]<data[i]) return false; } return false; }
00852     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; }
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 true; } return false; }
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; if(x.cols[0][i]<data[i]) return false; } return false; }
00855     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; }
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 true; } return false; }
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; if(x.cols[0][i]<data[i]) return false; } return false; }
00858     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; }
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 true; } return false; }
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; if(x.data[i]<data[i]) return false; } return false; }
00861 
00862     //! returns true if all elements are less than the corresponding element
00863     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; }
00864     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; }
00865     
00866     inline R& operator[](size_t i) { return data[i]; }
00867     inline const R& operator[](size_t i) const { return data[i]; }
00868     
00869     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); }
00870     R sum() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { ans+=data[--i]; } return ans; }
00871     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; }
00872     void abs() { size_t i=N; while(i!=0) { --i; data[i]=std::abs(data[i]); } }
00873     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; }
00874     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; }
00875     template<typename F> void apply(const F& f) { size_t i=N; while(i--!=0) data[i]=f(data[i]); }
00876     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; }
00877     
00878     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]; } }
00879     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]; } }
00880     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]; } }
00881     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]; } }
00882     
00883     inline Row<N,R> transpose() const ATTR_must_check {
00884       Row<N,R> ans=fmat_internal::NoInit();
00885       fmat_internal::tmemcpy<R>(ans.data,data,N);
00886       return ans;
00887     }
00888 
00889     inline std::string fmt(std::string const &numberFormat=defaultNumberFormat, 
00890       std::string const &firstLineStart="[",
00891       std::string const &nextLineStart="",
00892       std::string const &lastLineEnd="]\u1D40", // aka UTF-8 literal 'ᵀ'
00893       std::string const &rowBegin="",
00894       std::string const &elementSep="",
00895       std::string const &rowEnd="",
00896       std::string const &rowSep=" ") const
00897     {
00898       return fullfmt(&data[0],N,1,numberFormat,firstLineStart,nextLineStart,lastLineEnd,rowBegin,elementSep,rowEnd,rowSep);
00899     }
00900 
00901   protected:
00902     using Matrix<N,1,R>::data;
00903   };
00904   // with extern templates, g++ was having issues with the inline definition; clang was having issues with the out-of-line definition...
00905 #if !defined(__clang__) && defined(__GNUC__) && !(__GNUC__==4 && __GNUC_MINOR__<1)
00906   template<size_t N, typename R> const size_t Column<N,R>::HEIGHT=N;
00907   template<size_t N, typename R> const size_t Column<N,R>::WIDTH=1;
00908   template<size_t N, typename R> const size_t Column<N,R>::CAP=N;
00909 #endif
00910   
00911   
00912   template<size_t N, typename R=fmatReal>
00913   class Row : public Matrix<1,N,R> {
00914     template<size_t S, typename T> friend class SubVector;
00915     template<size_t S, typename T> friend class Column;
00916     template<size_t S, typename T> friend class Row;
00917   public:
00918     static const size_t HEIGHT=1;
00919     static const size_t WIDTH=N;
00920     static const size_t CAP=N;
00921     typedef R storage_t;
00922     typedef typename fmat_internal::unconst<R>::type out_t;
00923     
00924     Row(const fmat_internal::NoInit& noinit) : Matrix<1,N,R>(noinit) {}
00925     
00926     Row() : Matrix<1,N,R>() {}
00927     explicit Row(const R x) : Matrix<1,N,R>(x) {}
00928     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)]; } }
00929     Row(const SubVector<N,R>& x) : Matrix<1,N,R>(x.data) {}
00930     Row(const SubVector<N,const R>& x) : Matrix<1,N,R>(x.data) {}
00931     Row(const SubMatrix<1,N,R>& x) : Matrix<1,N,R>(x) {}
00932     Row(const SubMatrix<1,N,const R>& x) : Matrix<1,N,R>(x) {}
00933     Row(const Matrix<1,N,R>& x) : Matrix<1,N,R>(x) {}
00934     template<size_t S> explicit Row(const Row<S,R>& x, size_t srcOffset=0) : Matrix<1,N,R>() {
00935       size_t toCopy = std::min(N,S-srcOffset);
00936       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00937     }
00938     template<size_t S> explicit Row(const SubVector<S,R>& x, size_t srcOffset=0) : Matrix<1,N,R>() {
00939       size_t toCopy = std::min(N,S-srcOffset);
00940       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00941     }
00942     template<size_t S> explicit Row(const SubVector<S,const R>& x, size_t srcOffset=0) : Matrix<1,N,R>() {
00943       size_t toCopy = std::min(N,S-srcOffset);
00944       fmat_internal::tmemcpy<R>(data,&x.data[srcOffset],toCopy);
00945     }
00946     template<typename T> Row& importFrom(const T& x) { size_t i=N; while(i!=0) { --i; data[i]=x[i]; } return *this; }
00947     template<typename T> T exportTo() const { T x; size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00948     template<typename T> T& exportTo(T& x) const { size_t i=N; while(i!=0) { --i; x[i]=data[i]; } return x; }
00949     // provided by implicit SubVector constructors
00950     //operator SubVector<N,R>() { return SubVector<N,R>(data); }
00951     //operator SubVector<N,const R>() const { return SubVector<N,const R>(data); }
00952     
00953     Row& operator=(const R* x) { fmat_internal::tmemcpy<R>(data,x,CAP); return *this; }
00954     Row& operator=(R x) { fmat_internal::tmemset<R>(data,x,CAP); return *this; }
00955     Row& operator=(const SubVector<N,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00956     Row& operator=(const SubVector<N,const R>& x) { fmat_internal::tmemcpy<R>(data,x.data,N); return *this; }
00957     Row& operator=(const SubMatrix<1,N,R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00958     Row& operator=(const SubMatrix<1,N,const R>& x) { fmat_internal::tmemcpy<R>(data,x.cols[0].data,N); return *this; }
00959     Row& operator=(const Matrix<1,N,R>& x) { fmat_internal::tmemcpy<R>(data,x.data,CAP); return *this; }
00960     
00961     Row& operator+=(R x) { size_t i=N; while(i!=0) data[--i]+=x; return *this; }
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) { x=1/x; size_t i=N; while(i!=0) data[--i]*=x; return *this; }
00965     Row<N,out_t> operator+(R x) const { return Row<N,R>(*this)+=x; }
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-() const { Row<N,R> ans(*this); size_t i=N; while(i--!=0) ans.data[i]=-ans.data[i]; return ans; }
00970     
00971     friend Row<N,out_t> operator+(R x, const Row& a) { return a+x; }
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     
00975     Row& operator+=(const SubVector<N,R>& x) { size_t i=CAP; while(i--!=0) data[i]+=x.data[i]; return *this; }
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,const 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 SubMatrix<1,N,R>& x) { Matrix<1,N,R>::operator+=(x); 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,const 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 Matrix<1,N,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     
00986     Row operator+(const SubVector<N,R>& x) const { return Row(*this)+=x; }
00987     Row operator-(const SubVector<N,R>& x) const { return Row(*this)-=x; }
00988     Row operator+(const SubVector<N,const 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 SubMatrix<1,N,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,const 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 Matrix<1,N,R>& x) const { return Row(*this)+=x; }
00995     Row operator-(const Matrix<1,N,R>& x) const { return Row(*this)-=x; }
00996     
00997     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; }
00998     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; }
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; if(x.data[i]<data[i]) return false; } return false; }
01000     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; }
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 true; } return false; }
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; if(x.data[i]<data[i]) return false; } return false; }
01003     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; }
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 true; } return false; }
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; if(x.cols[i][0]<data[i]) return false; } return false; }
01006     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; }
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 true; } return false; }
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; if(x.cols[i][0]<data[i]) return false; } return false; }
01009     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; }
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 true; } return false; }
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; if(x.data[i]<data[i]) return false; } return false; }
01012     
01013     //! returns true if all elements are less than the corresponding element
01014     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; }
01015     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; }
01016     
01017     inline R& operator[](size_t i) { return data[i]; }
01018     inline const R& operator[](size_t i) const { return data[i]; }
01019     
01020     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); }
01021     R sum() const ATTR_must_check { R ans=0; size_t i=N; while(i!=0) { ans+=data[--i]; } return ans; }
01022     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; }
01023     void abs() { size_t i=N; while(i!=0) { --i; data[i]=std::abs(data[i]); } }
01024     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; }
01025     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; }
01026     template<typename F> void apply(const F& f) { size_t i=N; while(i--!=0) data[i]=f(data[i]); }
01027     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; }
01028     
01029     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]; } }
01030     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]; } }
01031     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]; } }
01032     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]; } }
01033     
01034     inline Column<N,R> transpose() const ATTR_must_check {
01035       Column<N,R> ans=fmat_internal::NoInit();
01036       fmat_internal::tmemcpy<R>(ans.data,data,N);
01037       return ans;
01038     }
01039 
01040     inline std::string fmt(std::string const &numberFormat=defaultNumberFormat, 
01041       std::string const &firstLineStart="[",
01042       std::string const &nextLineStart="",
01043       std::string const &lastLineEnd="]",
01044       std::string const &rowBegin="",
01045       std::string const &elementSep=" ",
01046       std::string const &rowEnd="",
01047       std::string const &rowSep="") const
01048     {
01049       return fullfmt(&data[0],1,N,numberFormat,firstLineStart,nextLineStart,lastLineEnd,rowBegin,elementSep,rowEnd,rowSep);
01050     }
01051 
01052   protected:
01053     using Matrix<1,N,R>::data;
01054   };
01055   
01056   
01057   extern const Column<2> ZERO2; //!< a length 2 column vector with all zeros (could also just use Column<2>(), but this is more semantic)
01058   extern const Column<3> ZERO3; //!< a length 3 column vector with all zeros (could also just use Column<3>(), but this is more semantic)
01059   extern const Column<4> ZEROH; //!< a length 4 column vector representing zero in homogenous coordinates (0,0,0,1)
01060   
01061   extern const Column<2> UNIT2_X; //!< a length 2 column with '1' in the first dimension
01062   extern const Column<2> UNIT2_Y; //!< a length 2 column with '1' in the second dimension
01063   
01064   extern const Column<3> UNIT3_X; //!< a length 3 column with '1' in the first dimension
01065   extern const Column<3> UNIT3_Y; //!< a length 3 column with '1' in the second dimension
01066   extern const Column<3> UNIT3_Z; //!< a length 3 column with '1' in the third dimension
01067   
01068   //! generic packing of N values into a Column<N> (note assumes fmatReal, see packT()
01069   inline Column<2> pack(fmatReal x, fmatReal y) { Column<2> v=fmat_internal::NoInit(); v.data[0]=x; v.data[1]=y; return v; }
01070   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; }
01071   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; }
01072   
01073   // alternative implementation, tail recursion faster?
01074   /*template<typename R> Column<2,R> pack(R x, R y) { R data[] = {x,y}; return Column<2,R>(data); }
01075   template<typename R> Column<3,R> pack(R x, R y, R z) { R data[] = {x,y,z}; return Column<3,R>(data); }
01076   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); }*/
01077   
01078   //! 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
01079   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; }
01080   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; }
01081   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; }
01082   
01083   //! packing columns: appending an element or concatenating two columns
01084   template<template<size_t N, typename R> class T, size_t N, typename R1, typename R2>
01085   Column<N+1,typename fmat_internal::unconst<R1>::type>
01086   pack(const T<N,R1>& x, R2 y) {
01087     Column<N+1,typename fmat_internal::unconst<R1>::type> data(x); data[N]=y; return data;
01088   }
01089   template<template<size_t N, typename R> class T, size_t N, typename R1, typename R2>
01090   Column<N+1,typename fmat_internal::unconst<R2>::type>
01091   pack(R1 x, const T<N,R2>& y) {
01092     Column<N+1,typename fmat_internal::unconst<R2>::type> data=fmat_internal::NoInit(); data[0]=x; SubVector<N>(data,1)=y; return data;
01093   }
01094   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>
01095   Column<N1+N2,typename fmat_internal::promotion_trait<R1,R2>::type>
01096   pack(const T1<N1,R1>& x, const T2<N2,R2>& y) {
01097     Column<N1+N2,typename fmat_internal::promotion_trait<R1,R2>::type> data(x); SubVector<N2>(data,N1)=y; return data;
01098   }
01099   
01100   // this is just to pick up subclasses
01101   template<size_t N, typename R1, typename R2>
01102   Column<N+1,typename fmat_internal::unconst<R1>::type> pack(const Column<N,R1>& x, R2 y) {
01103     Column<N+1,typename fmat_internal::unconst<R1>::type> data(x); data[N]=y; return data;
01104   }
01105   template<size_t N, typename R1, typename R2>
01106   Column<N+1,typename fmat_internal::unconst<R2>::type> pack(R1 x, const Column<N,R2>& y) {
01107     Column<N+1,typename fmat_internal::unconst<R2>::type> data=fmat_internal::NoInit(); data[0]=x; SubVector<N,R2>(data,1)=y; return data;
01108   }
01109   template<size_t N1, size_t N2, typename R>
01110   Column<N1+N2,typename fmat_internal::unconst<R>::type> pack(const Column<N1,R>& x, const Column<N2,R>& y) {
01111     Column<N1+N2,typename fmat_internal::unconst<R>::type> data(x); SubVector<N2>(data,N1)=y; return data;
01112   }
01113 
01114   // override: packing a row should return a row
01115   template<size_t N, typename R1, typename R2>
01116   Row<N+1,typename fmat_internal::unconst<R1>::type> pack(const Row<N,R1>& x, R2 y) {
01117     Row<N+1,typename fmat_internal::unconst<R1>::type> data(x); data[N]=y; return data;
01118   }
01119   template<size_t N, typename R1, typename R2>
01120   Row<N+1,typename fmat_internal::unconst<R2>::type> pack(R1 x, const Row<N,R2>& y) {
01121     Row<N+1,typename fmat_internal::unconst<R2>::type> data=fmat_internal::NoInit(); data[0]=x; SubVector<N,R2>(data,1)=y; return data;
01122   }
01123   template<size_t N1, size_t N2, typename R>
01124   Row<N1+N2,typename fmat_internal::unconst<R>::type> pack(const Row<N1,R>& x, const Row<N2,R>& y) {
01125     Row<N1+N2,typename fmat_internal::unconst<R>::type> data(x); SubVector<N2>(data,N1)=y; return data;
01126   }
01127   
01128   
01129   template<size_t N, typename R> inline std::ostream& operator<<(std::ostream& os, const SubVector<N,R>& x) {
01130     return os << x.fmt(); }
01131 
01132   template<size_t H, size_t W, typename R> inline std::ostream& operator<<(std::ostream& os, const SubMatrix<H,W,R>& x) {
01133     return os << x.fmt(); }
01134 
01135   template<size_t H, size_t W, typename R> inline std::ostream& operator<<(std::ostream& os, const Matrix<H,W,R>& x) {
01136     return os << x.fmt(); }
01137 
01138   template<size_t N, typename R> inline std::ostream& operator<<(std::ostream& os, const Column<N,R>& x) {
01139     return os << x.fmt(); }
01140 
01141   template<size_t N, typename R> inline std::ostream& operator<<(std::ostream& os, const Row<N,R>& x) {
01142     return os << x.fmt(); }
01143 
01144 
01145   
01146   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>
01147   inline Matrix<H,W,typename fmat_internal::promotion_trait<R1,R2>::type>
01148   operator*(const T1<H,N,R1>& a, const T2<N,W,R2>& b) {
01149     return fmat_internal::mmops<T1<H,N,R1>,T2<N,W,R2> >::multiply(a,b);
01150   }
01151   
01152   /*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>
01153   inline Matrix<D,D,typename fmat_internal::promotion_trait<R1,R2>::type>
01154   operator*(const T1<D,D,R1>& a, const T2<D,D,R2>& b) {
01155     return fmat_internal::mmops<T1<D,D,R1>,T2<D,D,R2> >::multiply(a,b);
01156   }*/
01157   
01158   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>
01159   inline T1<D,D,R1>&
01160   operator*=(T1<D,D,R1>& a, const T2<D,D,R2>& b) {
01161     a=fmat_internal::mmops<T1<D,D,R1>,T2<D,D,R2> >::multiply(a,b);
01162     return a;
01163   }
01164   
01165   template<template<size_t H, size_t W, typename R> class T2, size_t D, typename R1, typename R2>
01166   inline const SubMatrix<D,D,R1>&
01167   operator*=(const SubMatrix<D,D,R1>& a, const T2<D,D,R2>& b) {
01168     a=fmat_internal::mmops<SubMatrix<D,D,R1>,T2<D,D,R2> >::multiply(a,b);
01169     return a;
01170   }
01171   
01172   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>
01173   inline Column<H,typename fmat_internal::promotion_trait<R1,R2>::type>
01174   operator*(const T1<H,N,R1>& a, const T2<N,R2>& b) {
01175     return fmat_internal::mvops<T1<H,N,R1>,T2<N,R2> >::multiply(a,b);
01176   }
01177   
01178   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>
01179   inline Row<W,typename fmat_internal::promotion_trait<R1,R2>::type>
01180   operator*(const T1<N,R1>& a, const T2<N,W,R2>& b) {
01181     return fmat_internal::mvops<T2<N,W,R2>,T1<N,R1> >::multiply(a,b);
01182   }
01183   
01184   template<template<size_t N, typename R> class T, size_t N, typename R>
01185   inline fmat::Column<N,typename fmat_internal::unconst<R>::type>
01186   abs(const T<N,R>& v) {
01187     fmat::Column<N,typename fmat_internal::unconst<R>::type> ans=fmat_internal::NoInit();
01188     for(size_t i=N; i!=0; ) {
01189       --i;
01190       ans[i]=std::abs(v[i]);
01191     }
01192     return ans;
01193   }
01194 
01195   template<template<size_t H, size_t W, typename R> class T, size_t H, size_t W, typename R>
01196   inline fmat::Matrix<H,W,typename fmat_internal::unconst<R>::type>
01197   abs(const T<H,W,R>& m) {
01198     typedef typename fmat_internal::unconst<R>::type out_t;
01199     fmat::Matrix<H,W,out_t> ans=fmat_internal::NoInit();
01200     out_t* ad=&ans(0,0);
01201     const R* md=&m(0,0);
01202     for(size_t i=H*W; i!=0; ) {
01203       --i;
01204       ad[i]=std::abs(md[i]);
01205     }
01206     return ans;
01207   }
01208   
01209   template<typename R> inline R atan(const Column<2,R>& v) { return std::atan2(v[1],v[0]); }
01210   template<typename R> inline R atan(const Row<2,R>& v) { return std::atan2(v[1],v[0]); }
01211   template<typename R> inline R atan(const SubVector<2,R>& v) { return std::atan2(v[1],v[0]); }
01212   
01213   template<template<size_t N, typename R> class T1, template<size_t N, typename R> class T2, size_t N, typename R1, typename R2>
01214   typename fmat_internal::promotion_trait<R1,R2>::type
01215   dotProduct(const T1<N,R1>& a, const T2<N,R2>& b) {
01216     typename fmat_internal::promotion_trait<R1,R2>::type ans=0;
01217     size_t i=N;
01218     while(i--!=0)
01219       ans+=a[i]*b[i];
01220     return ans; 
01221   }
01222   // this version of dotProduct() gets picked up when using subclasses, which don't match the template forms above
01223   template<class Ta, class Tb>
01224   inline typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type
01225   dotProduct(const Ta& a, const Tb& b) {
01226     (void)sizeof(fmat_internal::CompileTimeAssert<Length_mismatch_or_non_vector,Ta::CAP==Tb::CAP && Ta::HEIGHT==Ta::CAP && Tb::HEIGHT==Tb::CAP>);
01227     typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type ans=0;
01228     size_t i=Ta::CAP;
01229     while(i--!=0)
01230       ans+=a[i]*b[i];
01231     return ans; 
01232   }
01233   
01234   template<class Ta, class Tb>
01235   inline Column<3,typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type>
01236   crossProduct(const Ta& a, const Tb& b) {
01237     return packT<typename fmat_internal::promotion_trait<typename Ta::storage_t,typename Tb::storage_t>::type>(
01238       a[1] * b[2] - a[2] * b[1],
01239       a[2] * b[0] - a[0] * b[2],
01240       a[0] * b[1] - a[1] * b[0]
01241     );
01242   }
01243   
01244   template<template<size_t H, size_t W, typename R> class M, typename R>
01245   typename fmat_internal::unconst<R>::type
01246   determinant(const M<2,2,R>& m) {
01247     return m(0,0) * m(1,1) - m(0,1) * m(1,0);
01248   }
01249   
01250   template<template<size_t H, size_t W, typename R> class M, typename R>
01251   typename fmat_internal::unconst<R>::type
01252   determinant(const M<3,3,R>& m) {
01253     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)
01254     - 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);
01255   }
01256   
01257   //! Computes and returns the inverse of a square matrix using Gauss-Jordan elimination
01258   /*! The computation is done with column-wise operations for computational efficiency.
01259    *  You can think of this as doing the inverse in transposed space: (mᵀ)⁻¹ == (m⁻¹)ᵀ */
01260   template<typename M>
01261   Matrix<M::HEIGHT,M::WIDTH,typename fmat_internal::unconst<typename M::storage_t>::type >
01262   invert(const M& m) {
01263     (void)sizeof(fmat_internal::CompileTimeAssert<NonSquare_Matrix,M::WIDTH==M::HEIGHT>);
01264     typedef typename fmat_internal::unconst<typename M::storage_t>::type R;
01265     const size_t DIM=M::HEIGHT;
01266     
01267     Matrix<DIM*2,DIM,R> x(m);
01268     for(unsigned int c=0; c<DIM; ++c)
01269       x(DIM+c,c)=1;
01270     
01271     for(unsigned int c=0; c<DIM; ++c) {
01272       // find pivot
01273       R mx=std::abs(x(c,c));
01274       unsigned int mxi=c;
01275       for(unsigned int r=c+1; r<DIM; ++r) {
01276         const R v=std::abs(x(c,r));
01277         if(v>mx) {
01278           mx=v;
01279           mxi=r;
01280         }
01281       }
01282       if(mx<std::numeric_limits<float>::epsilon())
01283         throw std::underflow_error("low rank matrix, non-invertable");
01284       
01285       // swap to put pivot in position
01286       Column<DIM*2,R> tmp = x.column(c);
01287       x.column(c) = x.column(mxi);
01288       x.column(mxi) = tmp;
01289       
01290       {
01291         const R p=x(c,c);
01292         for(unsigned int c2=c+1; c2<DIM*2; ++c2)
01293           x(c2,c)/=p;
01294         x(c,c)=1;
01295       }
01296       
01297       for(unsigned int r=c+1; r<DIM; ++r) {
01298         const R p = x(c,r);
01299         for(unsigned int c2=c+1; c2<DIM*2; ++c2)
01300           x(c2,r)-=x(c2,c)*p;
01301         x(c,r)=0;
01302       }
01303     }
01304     for(unsigned int c=0; c<DIM; ++c) {
01305       for(unsigned int r=0; r<c; ++r) {
01306         const R p = x(c,r);
01307         for(unsigned int c2=c+1; c2<DIM*2; ++c2)
01308           x(c2,r)-=x(c2,c)*p;
01309         x(c,r)=0;
01310       }
01311     }
01312     return SubMatrix<DIM,DIM,R>(x,DIM,0);
01313   }
01314   
01315   //! returns the determinant for 2x2 matrices
01316   template<template<size_t H, size_t W, typename R> class T, typename R>
01317   inline R det(const T<2,2,R>& m) {
01318     return m(0,0)*m(1,1) - m(1,0)*m(0,1);
01319   }
01320   
01321   //! returns the determinant for 3x3 matrices
01322   template<template<size_t H, size_t W, typename R> class T, typename R>
01323   inline R det(const T<3,3,R>& m) {
01324     const R cofactor0 = m(1,1)*m(2,2) - m(1,2)*m(2,1);
01325     const R cofactor1 = m(1,2)*m(2,0) - m(1,0)*m(2,2);
01326     const R cofactor2 = m(1,0)*m(2,1) - m(1,1)*m(2,0);
01327         return m(0,0)*cofactor0 + m(0,1)*cofactor1 + m(0,2)*cofactor2;
01328   }
01329   // todo: det() for higher dimensions
01330   
01331   
01332   // Performance specializations:
01333   template<template<size_t N, typename R> class V1, template<size_t N, typename R> class V2, typename R1, typename R2>
01334   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]; }
01335   template<template<size_t N, typename R> class V1, template<size_t N, typename R> class V2, typename R1, typename R2>
01336   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]; }
01337   template<template<size_t N, typename R> class V1, template<size_t N, typename R> class V2, typename R1, typename R2>
01338   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]; }
01339   
01340   namespace fmat_internal {
01341     inline float hypot(float a, float b) ATTR_pure ATTR_always_inline;
01342     inline float hypot(float a, float b) { return ::hypotf(a,b); }
01343     inline double hypot(double a, double b) ATTR_pure ATTR_always_inline;
01344     inline double hypot(double a, double b) { return ::hypot(a,b); }
01345 #ifndef PLATFORM_APERIOS
01346     inline long double hypot(long double a, long double b) ATTR_pure ATTR_always_inline;
01347     inline long double hypot(long double a, long double b) { return ::hypotl(a,b); }
01348 #endif
01349     template<class T> T hypot(T a, T b) { return std::sqrt(a*a,b*b); }
01350   }
01351   
01352   template<> inline fmatReal Column<2,fmatReal>::norm() const { return fmat_internal::hypot(data[0],data[1]); }
01353   template<> inline fmatReal Column<3,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01354   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]); }
01355   template<> inline fmatReal SubVector<2,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1]); }
01356   template<> inline fmatReal SubVector<3,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01357   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]); }
01358   template<> inline fmatReal SubVector<2,const fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1]); }
01359   template<> inline fmatReal SubVector<3,const fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01360   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]); }
01361   template<> inline fmatReal Row<2,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1]); }
01362   template<> inline fmatReal Row<3,fmatReal>::norm() const { return std::sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01363   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]); }
01364 
01365   template<> inline fmatReal Column<2,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01366   template<> inline fmatReal Column<3,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01367   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]); }
01368   template<> inline fmatReal SubVector<2,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01369   template<> inline fmatReal SubVector<3,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01370   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]); }
01371   template<> inline fmatReal SubVector<2,const fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01372   template<> inline fmatReal SubVector<3,const fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01373   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]); }
01374   template<> inline fmatReal Row<2,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1]); }
01375   template<> inline fmatReal Row<3,fmatReal>::sumSq() const { return (data[0]*data[0] + data[1]*data[1] + data[2]*data[2]); }
01376   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]); }
01377   
01378 
01379   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; }
01380   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; }
01381   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; }
01382   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; }
01383   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; }
01384   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; }
01385   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; }
01386   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; }
01387   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; }
01388 
01389   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; }
01390   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; }
01391   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; }
01392   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; }
01393   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; }
01394   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; }
01395   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; }
01396   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; }
01397   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; }
01398   
01399   template<> inline const SubVector<2,fmatReal>& SubVector<2,fmatReal>::operator*=(fmatReal x) const { data[0]*=x; data[1]*=x; return *this; }
01400   template<> inline const SubVector<3,fmatReal>& SubVector<3,fmatReal>::operator*=(fmatReal x) const { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01401   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; }
01402   template<> inline Matrix<2,1,fmatReal>& Matrix<2,1,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; return *this; }
01403   template<> inline Matrix<3,1,fmatReal>& Matrix<3,1,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01404   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; }
01405   template<> inline Column<2,fmatReal>& Column<2,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; return *this; }
01406   template<> inline Column<3,fmatReal>& Column<3,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01407   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; }
01408   template<> inline Row<2,fmatReal>& Row<2,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; return *this; }
01409   template<> inline Row<3,fmatReal>& Row<3,fmatReal>::operator*=(fmatReal x) { data[0]*=x; data[1]*=x; data[2]*=x; return *this; }
01410   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; }
01411 
01412   template<> inline const SubVector<2,fmatReal>& SubVector<2,fmatReal>::operator/=(fmatReal x) const { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01413   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; }
01414   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; }
01415   template<> inline Matrix<2,1,fmatReal>& Matrix<2,1,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01416   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; }
01417   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; }
01418   template<> inline Column<2,fmatReal>& Column<2,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01419   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; }
01420   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; }
01421   template<> inline Row<2,fmatReal>& Row<2,fmatReal>::operator/=(fmatReal x) { x=1/x; data[0]*=x; data[1]*=x; return *this; }
01422   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; }
01423   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; }
01424 
01425   namespace fmat_internal {
01426     
01427     template<template<size_t H, size_t W, typename R> class T1, template<size_t N, typename R> class T2, typename R1, typename R2>
01428     struct mvops<T1<2,2,R1>,T2<2,R2> > {
01429       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01430       inline static Column<2,R> multiply(const T1<2,2,R1>& ma, const T2<2,R2>& b) {
01431         Column<2,R> ans=fmat_internal::NoInit();
01432         const R1 *a=&ma(0,0);
01433         ans[0] = a[0*2+0]*b[0] + a[1*2+0]*b[1];
01434         ans[1] = a[0*2+1]*b[0] + a[1*2+1]*b[1];
01435         return ans;
01436       }
01437       inline static Row<2,R> multiply(const T2<2,R2>& b, const T1<2,2,R1>& ma) {
01438         Row<2,R> ans=fmat_internal::NoInit();
01439         const R1 *a=&ma(0,0);
01440         ans[0] = a[0*2+0]*b[0] + a[0*2+1]*b[1];
01441         ans[1] = a[1*2+0]*b[0] + a[1*2+1]*b[1];
01442         return ans;
01443       }
01444     };
01445     template<template<size_t H, size_t W, typename R> class T1, template<size_t N, typename R> class T2, typename R1, typename R2>
01446     struct mvops<T1<3,3,R1>,T2<3,R2> > {
01447       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01448       inline static Column<3,R> multiply(const T1<3,3,R1>& ma, const T2<3,R2>& b) {
01449         Column<3,R> ans=fmat_internal::NoInit();
01450         const R *a=&ma(0,0);
01451         ans[0] = a[0*3+0]*b[0] + a[1*3+0]*b[1] + a[2*3+0]*b[2];
01452         ans[1] = a[0*3+1]*b[0] + a[1*3+1]*b[1] + a[2*3+1]*b[2];
01453         ans[2] = a[0*3+2]*b[0] + a[1*3+2]*b[1] + a[2*3+2]*b[2];
01454         return ans;
01455       }
01456       inline static Row<3,R> multiply(const T2<3,R2>& b, const T1<3,3,R1>& ma) {
01457         Row<3,R> ans=fmat_internal::NoInit();
01458         const R *a=&ma(0,0);
01459         ans[0] = a[0*3+0]*b[0] + a[0*3+1]*b[1] + a[0*3+2]*b[2];
01460         ans[1] = a[1*3+0]*b[0] + a[1*3+1]*b[1] + a[1*3+2]*b[2];
01461         ans[2] = a[2*3+0]*b[0] + a[2*3+1]*b[1] + a[2*3+2]*b[2];
01462         return ans;
01463       }
01464     };
01465     template<template<size_t H, size_t W, typename R> class T1, template<size_t N, typename R> class T2, typename R1, typename R2>
01466     struct mvops<T1<4,4,R1>,T2<4,R2> > {
01467       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01468       inline static Column<4,R> multiply(const T1<4,4,R1>& ma, const T2<4,R2>& b) {
01469         Column<4,R> ans=fmat_internal::NoInit();
01470         const R *a=&ma(0,0);
01471         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];
01472         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];
01473         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];
01474         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];
01475         return ans;
01476       }
01477       inline static Row<4,R> multiply(const T2<4,R2>& b, const T1<4,4,R1>& ma) {
01478         Row<4,R> ans=fmat_internal::NoInit();
01479         const R *a=&ma(0,0);
01480         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];
01481         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];
01482         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];
01483         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];
01484         return ans;
01485       }
01486     };
01487 
01488     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>
01489     struct mmops<T1<2,2,R1>,T2<2,2,R2> > {
01490       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01491       inline static Matrix<2,2,R> multiply(const T1<2,2,R1>& ma, const T2<2,2,R2>& mb) {
01492         Matrix<2,2,R> mans=fmat_internal::NoInit();
01493         R *ans=&mans(0,0);
01494         const R1 *a=&ma(0,0);
01495         const R2 *b=&mb(0,0);
01496         ans[0+2*0] = a[0+2*0]*b[0+2*0] + a[0+2*1]*b[1+2*0];
01497         ans[1+2*0] = a[1+2*0]*b[0+2*0] + a[1+2*1]*b[1+2*0];
01498         ans[0+2*1] = a[0+2*0]*b[0+2*1] + a[0+2*1]*b[1+2*1];
01499         ans[1+2*1] = a[1+2*0]*b[0+2*1] + a[1+2*1]*b[1+2*1];
01500         return mans;
01501       }
01502     };
01503     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>
01504     struct mmops<T1<3,3,R1>,T2<3,3,R2> > {
01505       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01506       inline static Matrix<3,3,R> multiply(const T1<3,3,R1>& ma, const T2<3,3,R2>& mb) {
01507         Matrix<3,3,R> mans=fmat_internal::NoInit();
01508         R *ans=&mans(0,0);
01509         const R1 *a=&ma(0,0);
01510         const R2 *b=&mb(0,0);
01511         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];
01512         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];
01513         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];
01514         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];
01515         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];
01516         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];
01517         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];
01518         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];
01519         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];
01520         return mans;
01521       }
01522     };
01523     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>
01524     struct mmops<T1<4,4,R1>,T2<4,4,R2> > {
01525       typedef typename fmat_internal::promotion_trait<R1,R2>::type R;
01526       inline static Matrix<4,4,R> multiply(const T1<4,4,R1>& ma, const T2<4,4,R2>& mb) {
01527         Matrix<4,4,R> mans=fmat_internal::NoInit();
01528         R *ans=&mans(0,0);
01529         const R1 *a=&ma(0,0);
01530         const R2 *b=&mb(0,0);
01531         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];
01532         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];
01533         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];
01534         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];
01535         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];
01536         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];
01537         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];
01538         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];
01539         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];
01540         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];
01541         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];
01542         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];
01543         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];
01544         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];
01545         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];
01546         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];
01547         return mans;
01548       }
01549     };
01550   }
01551 
01552   extern template class SubVector<3,fmatReal>;
01553   extern template class Column<3,fmatReal>;
01554   extern template class SubMatrix<3,3,fmatReal>;
01555   extern template class Matrix<3,4,fmatReal>;
01556 
01557 } // namespace
01558 
01559 #endif
01560 
01561 /*! @file
01562  * @brief Defines fmat namespace, for fixed-dimension matrix computation
01563  * @author Ethan Tira-Thompson (ejt) (Creator)
01564  */

Tekkotsu v5.1CVS
Generated Sat May 4 06:32:48 2013 by Doxygen 1.6.3