1 /**************************************************************************/ 2 /* Copyright 2012 Tim Day */ 3 /* */ 4 /* This file is part of Evolvotron */ 5 /* */ 6 /* Evolvotron is free software: you can redistribute it and/or modify */ 7 /* it under the terms of the GNU General Public License as published by */ 8 /* the Free Software Foundation, either version 3 of the License, or */ 9 /* (at your option) any later version. */ 10 /* */ 11 /* Evolvotron is distributed in the hope that it will be useful, */ 12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 14 /* GNU General Public License for more details. */ 15 /* */ 16 /* You should have received a copy of the GNU General Public License */ 17 /* along with Evolvotron. If not, see <http://www.gnu.org/licenses/>. */ 18 /**************************************************************************/ 19 20 /*! \file 21 \brief Interface for class Matrix. 22 */ 23 24 #ifndef _matrix_h_ 25 #define _matrix_h_ 26 27 #include "useful.h" 28 #include "tuple.h" 29 30 // Fwd declaration of helper class. 31 template <uint FC,uint R,uint C,class T> class MatrixHelperSumCofactorDeterminantProducts; 32 template <uint R,uint C,uint ROWS,uint COLS,class T> class MatrixHelperInvert; 33 34 35 //! Common base for general and specialised cases. 36 /*! Avoids having to reimplement some functions in Matrix<1,1,T> specialisation. 37 */ 38 template <uint R,uint C,class T> class MatrixBase : public Tuple<R,Tuple<C,T> > 39 { 40 public: 41 //! Null constructor. 42 MatrixBase<R,C,T>() 43 {} 44 45 //! Copy constructor. 46 MatrixBase<R,C,T>(const MatrixBase<R,C,T>& t) 47 :Tuple<R,Tuple<C,T> >(t) 48 {} 49 50 ////! Destructor. 51 //~MatrixBase<R,C,T>() 52 // {} 53 rows()54 uint rows() const 55 { 56 return R; 57 } 58 cols()59 uint cols() const 60 { 61 return C; 62 } 63 cofactor_sign(uint mr,uint mc)64 static int cofactor_sign(uint mr,uint mc) 65 { 66 return ( ((mr+mc)&1) ? -1 : 1); 67 } 68 cofactor_sign(uint mr,uint mc,const T v)69 static const T cofactor_sign(uint mr,uint mc,const T v) 70 { 71 return ( ((mr+mc)&1) ? -v : v); 72 } 73 write(std::ostream & out)74 std::ostream& write(std::ostream& out) const 75 { 76 for (uint r=0;r<R;r++) 77 { 78 (*this)[r].write(out); 79 out << "\n"; 80 } 81 return out; 82 } 83 }; 84 85 //! Class to hold a fixed size matrix of elements 86 template <uint R,uint C,class T> class Matrix : public MatrixBase<R,C,T> 87 { 88 protected: 89 90 91 public: 92 93 //! Null constructor. 94 Matrix<R,C,T>() 95 :MatrixBase<R,C,T>() 96 {} 97 98 //! Copy constructor. 99 Matrix<R,C,T>(const Matrix<R,C,T>& m) 100 :MatrixBase<R,C,T>(m) 101 {} 102 103 //! Construct minor matrix (from a larger matrix) 104 Matrix<R,C,T>(uint mr,uint mc,const Matrix<R+1,C+1,T>& m) 105 :MatrixBase<R,C,T>() 106 { 107 m.extract_minor(mr,mc,*this); 108 } 109 110 ////! Destructor. 111 //~Matrix<R,C,T>() 112 // {} 113 114 void operator*=(const T& v) 115 { 116 for (uint r=0;r<R;r++) 117 { 118 (*this)[r]*=v; 119 } 120 } 121 transposed()122 Matrix<C,R,T> transposed() const 123 { 124 Matrix<C,R,T> ret; 125 for (uint r=0;r<R;r++) 126 { 127 for (uint c=0;c<C;c++) 128 { 129 ret[c][r]=(*this)[r][c]; 130 } 131 } 132 return ret; 133 } 134 135 //! Puts the minor matrix into an argument 136 /*! Would have preferred to call this just "minor" but it's a macro. 137 */ extract_minor(uint mr,uint mc,Matrix<R-1,C-1,T> & m)138 void extract_minor(uint mr,uint mc,Matrix<R-1,C-1,T>& m) const 139 { 140 assert(mr<R); 141 assert(mc<C); 142 143 uint r; 144 uint rm; 145 for (r=0,rm=0;r<R;r++) 146 { 147 if (r!=mr) 148 { 149 uint c; 150 uint cm; 151 for (c=0,cm=0;c<C;c++) 152 { 153 if (c!=mc) 154 { 155 m[rm][cm]=(*this)[r][c]; 156 cm++; 157 } 158 } 159 rm++; 160 } 161 } 162 } 163 164 //! Template member for extracting minors when row and column to be eliminated are known at compile time. extract_minor(Matrix<R-1,C-1,T> & m)165 template <uint SKIP_R,uint SKIP_C> void extract_minor(Matrix<R-1,C-1,T>& m) const 166 { 167 TupleHelperDoubleCopyEliminate<R-2,SKIP_R,SKIP_C,R-1,C-1,T>::execute(m,*this); 168 } 169 determinant()170 T determinant() const 171 { 172 /* Old code calls runtime minor generator: not efficient code. 173 T ret(0); 174 for (uint c=0;c<C;c++) 175 { 176 ret+=(*this)[0][c]*cofactor_sign(0,c,Matrix<R-1,C-1,T>(0,c,*this).determinant()); 177 } 178 return ret; 179 */ 180 181 // Better version uses metaprogramming to expand to straight-line code. 182 return MatrixHelperSumCofactorDeterminantProducts<C-1,R,C,T>::execute(*this); 183 } 184 inverted()185 Matrix<R,C,T> inverted() const 186 { 187 Matrix<C,R,T> ret; 188 189 /* Old code calls runtime minor generator: not efficient code. 190 for (uint r=0;r<R;r++) 191 { 192 for (uint c=0;c<C;c++) 193 { 194 ret[c][r]=cofactor_sign(r,c,Matrix<R-1,C-1,T>(r,c,(*this)).determinant()); 195 } 196 } 197 */ 198 199 // Better version uses metaprogramming to expand to straight-line code. 200 MatrixHelperInvert<R-1,C-1,R,C,T>::execute(ret,(*this)); 201 202 ret*=(T(1.0)/determinant()); 203 204 return ret; 205 } 206 }; 207 208 //! Matrix multiplication 209 /*! \todo Check assembler code. Want loops to unroll - use template recursion ? 210 */ 211 template <uint AR,uint N,uint BC,class T> inline const Matrix<AR,BC,T> operator*(const Matrix<AR,N,T>& a,const Matrix<N,BC,T>& b) 212 { 213 Matrix<AR,BC,T> ret; 214 for (uint r=0;r<AR;r++) 215 for (uint c=0;c<BC;c++) 216 { 217 T t(0); 218 for (uint i=0;i<N;i++) 219 { 220 t+=a[r][i]*b[i][c]; 221 } 222 ret[r][c]=t; 223 } 224 return ret; 225 } 226 227 //! Matrix x tuple multiplication 228 /*! \todo Check assembler code. Want loops to unroll - use template recursion ? 229 */ 230 template <uint R,uint C,class T> inline const Tuple<R,T> operator*(const Matrix<R,C,T>& m,const Tuple<C,T>& v) 231 { 232 Tuple<R,T> ret; 233 for (uint r=0;r<R;r++) 234 { 235 T t(0); 236 for (uint c=0;c<C;c++) 237 { 238 t+=m[r][c]*v[c]; 239 } 240 ret[r]=t; 241 } 242 return ret; 243 } 244 245 246 //! (Partial) specialisation for 1x1 matrix 247 /*! NB Has no extract_minor method because doesn't make sense for 1x1 matrix. 248 */ 249 template <class T> class Matrix<1,1,T> : public MatrixBase<1,1,T> 250 { 251 protected: 252 253 254 public: 255 256 //! Null constructor. 257 Matrix<1,1,T>() 258 :MatrixBase<1,1,T>() 259 {} 260 261 //! Copy constructor. 262 Matrix<1,1,T>(const Matrix<1,1,T>& t) 263 :MatrixBase<1,1,T>(t) 264 {} 265 266 //! Construct minor matrix 267 Matrix<1,1,T>(uint mr,uint mc,const Matrix<2,2,T>& m) 268 :MatrixBase<R,C,T>() 269 { 270 m.extract_minor(mr,mc,*this); 271 } 272 273 //! Convenient constructor 274 Matrix<1,1,T>(T v00) 275 :MatrixBase<1,1,T>() 276 { 277 (*this)[0][0]=v00; 278 } 279 280 ////! Destructor. 281 //~Matrix<1,1,T>() 282 // {} 283 transposed()284 Matrix<1,1,T> transposed() const 285 { 286 return (*this); 287 } 288 289 //NB minor of 1x1 matrix makes no sense. 290 //void extract_minor(uint mr,uint mc,Matrix<R-1,C-1,T>& m) const 291 determinant()292 T determinant() const 293 { 294 return (*this)[0][0]; 295 } 296 inverted()297 Matrix<1,1,T> inverted() const 298 { 299 return Matrix<1,1,T>(T(1.0)/(*this)[0][0]); 300 } 301 }; 302 303 //! (Partial) specialisation for 2x2 matrix 304 template <class T> class Matrix<2,2,T> : public MatrixBase<2,2,T> 305 { 306 protected: 307 308 309 public: 310 311 //! Null constructor. 312 Matrix<2,2,T>() 313 :MatrixBase<2,2,T>() 314 {} 315 316 //! Copy constructor. 317 Matrix<2,2,T>(const Matrix<2,2,T>& t) 318 :MatrixBase<2,2,T>(t) 319 {} 320 321 //! Construct minor matrix 322 Matrix<2,2,T>(uint mr,uint mc,const Matrix<3,3,T>& m) 323 :MatrixBase<2,2,T>() 324 { 325 m.extract_minor(mr,mc,*this); 326 } 327 328 //! Convenient constructor 329 Matrix<2,2,T>(T v00,T v01,T v10,T v11) 330 :MatrixBase<2,2,T>() 331 { 332 (*this)[0][0]=v00; 333 (*this)[0][1]=v01; 334 (*this)[1][0]=v10; 335 (*this)[1][1]=v11; 336 } 337 338 ////! Destructor. 339 //~Matrix<1,1,T>() 340 // {} 341 transposed()342 Matrix<2,2,T> transposed() const 343 { 344 return Matrix<2,2,T>((*this)[0][0],(*this)[1][0],(*this)[0][1],(*this)[1][1]); 345 } 346 extract_minor(uint mr,uint mc,Matrix<1,1,T> & m)347 void extract_minor(uint mr,uint mc,Matrix<1,1,T>& m) const 348 { 349 assert(mr==0 || mr==1); 350 assert(mc==0 || mc==1); 351 m[0][0]=(*this)[1-mr][1-mc]; 352 } 353 354 //! Template member for extracting minors when row and column to be eliminated are known at compile time. extract_minor(Matrix<1,1,T> & m)355 template <uint SKIP_R,uint SKIP_C> void extract_minor(Matrix<1,1,T>& m) const 356 { 357 assert(SKIP_R==0 || SKIP_R==1); 358 assert(SKIP_C==0 || SKIP_C==1); 359 m[0][0]=(*this)[1-SKIP_R][1-SKIP_C]; 360 } 361 determinant()362 T determinant() const 363 { 364 return (*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0]; 365 } 366 inverted()367 Matrix<2,2,T> inverted() const 368 { 369 Matrix<2,2,T> ret((*this)[1][1],-(*this)[0][1],-(*this)[1][0],(*this)[0][0]); 370 ret*=(T(1.0)/determinant()); 371 return ret; 372 } 373 }; 374 375 template <uint FC,uint R,uint C,class T> class MatrixHelperSumCofactorDeterminantProducts 376 { 377 public: execute(const Matrix<R,C,T> & m)378 static T execute(const Matrix<R,C,T>& m) 379 { 380 Matrix<R-1,C-1,T> minor_matrix; 381 382 // Would prefer to use 383 //m.extract_minor<0,FC>(minor_matrix); 384 // but compiler doesn't seem to like it (problem with partial specialisation?) 385 TupleHelperDoubleCopyEliminate<R-2,0,FC,R-1,C-1,T>::execute(minor_matrix,m); 386 387 return 388 m[0][FC]*((FC&1) ? -1.0f : 1.0f)*minor_matrix.determinant() 389 + 390 MatrixHelperSumCofactorDeterminantProducts<FC-1,R,C,T>::execute(m); 391 ; 392 } 393 }; 394 395 template <uint R,uint C,class T> class MatrixHelperSumCofactorDeterminantProducts<0,R,C,T> 396 { 397 public: execute(const Matrix<R,C,T> & m)398 static float execute(const Matrix<R,C,T>& m) 399 { 400 Matrix<R-1,C-1,T> minor_matrix; 401 TupleHelperDoubleCopyEliminate<R-2,0,0,R-1,C-1,T>::execute(minor_matrix,m); 402 return m[0][0]*minor_matrix.determinant(); 403 } 404 }; 405 406 407 template <uint R,uint C,uint ROWS,uint COLS,class T> class MatrixHelperInvert 408 { 409 public: execute(Matrix<COLS,ROWS,T> & m_out,const Matrix<ROWS,COLS,T> & m_in)410 static void execute(Matrix<COLS,ROWS,T>& m_out,const Matrix<ROWS,COLS,T>& m_in) 411 { 412 Matrix<ROWS-1,COLS-1,T> minor_matrix; 413 TupleHelperDoubleCopyEliminate<ROWS-2,R,C,ROWS-1,COLS-1,T>::execute(minor_matrix,m_in); 414 m_out[C][R]=Matrix<ROWS,COLS,T>::cofactor_sign(R,C,minor_matrix.determinant()); 415 MatrixHelperInvert<R,C-1,ROWS,COLS,T>::execute(m_out,m_in); 416 } 417 }; 418 419 template <uint R,uint ROWS,uint COLS,class T> class MatrixHelperInvert<R,0,ROWS,COLS,T> 420 { 421 public: execute(Matrix<COLS,ROWS,T> & m_out,const Matrix<ROWS,COLS,T> & m_in)422 static void execute(Matrix<COLS,ROWS,T>& m_out,const Matrix<ROWS,COLS,T>& m_in) 423 { 424 Matrix<ROWS-1,COLS-1,T> minor_matrix; 425 TupleHelperDoubleCopyEliminate<ROWS-2,R,0,ROWS-1,COLS-1,T>::execute(minor_matrix,m_in); 426 m_out[0][R]=Matrix<ROWS,COLS,T>::cofactor_sign(R,0,minor_matrix.determinant()); 427 MatrixHelperInvert<R-1,COLS-1,ROWS,COLS,T>::execute(m_out,m_in); 428 } 429 }; 430 431 template <uint ROWS,uint COLS,class T> class MatrixHelperInvert<0,0,ROWS,COLS,T> 432 { 433 public: execute(Matrix<COLS,ROWS,T> & m_out,const Matrix<ROWS,COLS,T> & m_in)434 static void execute(Matrix<COLS,ROWS,T>& m_out,const Matrix<ROWS,COLS,T>& m_in) 435 { 436 Matrix<ROWS-1,COLS-1,T> minor_matrix; 437 TupleHelperDoubleCopyEliminate<ROWS-2,0,0,ROWS-1,COLS-1,T>::execute(minor_matrix,m_in); 438 m_out[0][0]=Matrix<ROWS,COLS,T>::cofactor_sign(0,0,minor_matrix.determinant()); 439 } 440 }; 441 442 //! 3x3 matrix class 443 class Matrix33 : public Matrix<3,3,float> 444 { 445 public: Matrix33()446 Matrix33() 447 {} Matrix33(const Matrix33 & m)448 Matrix33(const Matrix33& m) 449 :Matrix<3,3,float>(m) 450 {} 451 }; 452 453 class Matrix33RotateX : public Matrix33 454 { 455 public: Matrix33RotateX(float a)456 Matrix33RotateX(float a) 457 { 458 const float sa=sin(a); 459 const float ca=cos(a); 460 (*this)[0][0]=1.0f;(*this)[0][1]=0.0f;(*this)[0][2]=0.0f; 461 (*this)[1][0]=0.0f;(*this)[1][1]= ca;(*this)[1][2]= -sa; 462 (*this)[2][0]=0.0f;(*this)[2][1]= sa;(*this)[2][2]= ca; 463 } 464 }; 465 466 class Matrix33RotateY : public Matrix33 467 { 468 public: Matrix33RotateY(float a)469 Matrix33RotateY(float a) 470 { 471 const float sa=sin(a); 472 const float ca=cos(a); 473 (*this)[0][0]= ca;(*this)[0][1]=0.0f;(*this)[0][2]= sa; 474 (*this)[1][0]= -sa;(*this)[1][1]=1.0f;(*this)[1][2]= ca; 475 (*this)[2][0]=0.0f;(*this)[2][1]=0.0f;(*this)[2][2]=0.0f; 476 } 477 }; 478 479 class Matrix33RotateZ : public Matrix33 480 { 481 public: Matrix33RotateZ(float a)482 Matrix33RotateZ(float a) 483 { 484 const float sa=sin(a); 485 const float ca=cos(a); 486 (*this)[0][0]= ca;(*this)[0][1]= -sa;(*this)[0][2]=0.0f; 487 (*this)[1][0]= sa;(*this)[1][1]= ca;(*this)[1][2]=0.0f; 488 (*this)[2][0]=0.0f;(*this)[2][1]=0.0f;(*this)[2][2]=1.0f; 489 } 490 }; 491 492 //! Tests basic matrix functionality. 493 extern void testmatrix(); 494 495 #endif 496 497