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