TexGen
Matrix.h
Go to the documentation of this file.
1/*=============================================================================
2TexGen: Geometric textile modeller.
3Copyright (C) 2006 Martin Sherburn
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18=============================================================================*/
19
20#pragma once
21
22#include <ostream>
23#include <iomanip>
24#include <assert.h>
25
26
27namespace TexGen
28{
29 using namespace std;
30
32 class CMatrix
33 {
34 public:
35 CMatrix();
36 CMatrix(int iHeight, int iWidth);
37 CMatrix(const CMatrix &CopyMe);
38 ~CMatrix(void);
39
40 void Initialise(int iHeight, int iWidth);
41 void InitialiseIdentity(int iSize);
42
44 CMatrix &GetSubMatrix(CMatrix &SubMatrix, int iRow, int iColumn) const;
45 void SetSubMatrix( CMatrix &SubMatrix, int iRow, int iColumn );
46 void ZeroMatrix();
47 double &operator() (int i, int j);
48 const double &operator() (int i, int j) const;
49 const double GetValue(int i, int j) const;
50 void SetValue(int i, int j, double dVal);
51
52 CMatrix operator * (const CMatrix &RightMatrix) const; // These functions should not be used where performance is critical
53 CMatrix operator * (double dRight) const; // removed because they are not efficient
54 CMatrix operator + (const CMatrix &RightMatrix) const; // Use EqualsMultiple functions instead or += operator
55 CMatrix operator - (const CMatrix &RightMatrix) const;
56
57 CMatrix &operator *= (double dRight);
58 CMatrix &operator /= (double dRight);
59 CMatrix &operator += (const CMatrix &RightMatrix);
60 CMatrix &operator -= (const CMatrix &RightMatrix);
61 CMatrix &operator = (const CMatrix &RightMatrix);
62 double GetDeterminant() const;
63 double GetInverse(CMatrix &Inverse) const;
64 void GetSquareRoot(CMatrix &Root) const;
65 void GetEigen(CMatrix &EigenVectors, CMatrix &EigenValues) const;
66 void GetPolarDecomposition(CMatrix &U, CMatrix &P) const;
67// operator bool() const;
68 bool Empty() const;
69 int GetHeight() const;
70 int GetWidth() const;
71 void SwapRows(int iRow1, int iRow2);
72 void SwapColumns(int iColumn1, int iColumn2);
73 void DivideRow(int iRow, double dDivisor);
74 void DivideColumn(int iColumn, double dDivisor);
75 void SubtractRow(int iRow1, int iRow2, double dScale);
76 void SubtractColumn(int iColumn1, int iColumn2, double dScale);
77 void Identity();
78
80
83 CMatrix &EqualsMultiple(const CMatrix &LeftMatrix, const CMatrix &RightMatrix);
85
88 CMatrix &EqualsTransposeMultiple(const CMatrix &LeftMatrix, const CMatrix &RightMatrix);
90
93 CMatrix &EqualsMultipleTranspose(const CMatrix &LeftMatrix, const CMatrix &RightMatrix);
94
95 void PrintMatrix(char szMatrixName[], ostream &Output = cout, int iWidth = 16, bool bScientific = true);
96
97 protected:
98 double GetInverseSlow(CMatrix &Inverse) const;
101 double *m_dMatrix;
102 };
103
105 : m_iWidth(0)
106 , m_iHeight(0)
107 , m_dMatrix(NULL)
108 {
109 }
110
111 inline CMatrix::CMatrix(int iHeight, int iWidth)
112 : m_iWidth(iWidth)
113 , m_iHeight(iHeight)
114 {
115 m_dMatrix = new double [m_iWidth*m_iHeight];
116 ZeroMatrix();
117 }
118
119 inline CMatrix::CMatrix(const CMatrix &CopyMe)
120 : m_iWidth(0)
121 , m_iHeight(0)
122 , m_dMatrix(NULL)
123 {
124 (*this) = CopyMe;
125 }
126
127
128 inline CMatrix::~CMatrix(void)
129 {
130 if (m_dMatrix)
131 delete [] m_dMatrix;
132 }
133
134 inline CMatrix &CMatrix::operator = (const CMatrix &RightMatrix)
135 {
136 if (m_iHeight != RightMatrix.m_iHeight || m_iWidth != RightMatrix.m_iWidth)
137 {
138 Initialise(RightMatrix.m_iHeight, RightMatrix.m_iWidth);
139 }
140 memcpy(m_dMatrix, RightMatrix.m_dMatrix, m_iWidth*m_iHeight*sizeof(double));
141 return *this;
142 }
143
144 inline void CMatrix::Initialise(int iHeight, int iWidth)
145 {
146 assert(iHeight*iWidth > 0);
147 if (m_dMatrix)
148 delete [] m_dMatrix;
149 m_iWidth = iWidth;
150 m_iHeight = iHeight;
151 m_dMatrix = new double [m_iWidth*m_iHeight];
152 ZeroMatrix();
153 }
154
155 inline void CMatrix::InitialiseIdentity(int iSize)
156 {
157 assert(iSize > 0);
158 if (m_dMatrix)
159 delete [] m_dMatrix;
160 m_iWidth = iSize;
161 m_iHeight = iSize;
162 m_dMatrix = new double [iSize*iSize];
163 Identity();
164 }
165
166/* inline CMatrix::operator bool() const
167 {
168 return (m_iWidth && m_iHeight);
169 }*/
170
171 inline bool CMatrix::Empty() const
172 {
173 return (m_iWidth==0 || m_iHeight==0);
174 }
175
176 inline int CMatrix::GetHeight() const
177 {
178 return m_iHeight;
179 }
180
181 inline int CMatrix::GetWidth() const
182 {
183 return m_iWidth;
184 }
185
186 inline double &CMatrix::operator() (int i, int j)
187 {
188 assert(i >= 0 && i < m_iHeight && j >= 0 && j < m_iWidth);
189
190 return m_dMatrix[i*m_iWidth+j];
191 }
192
193 inline const double &CMatrix::operator() (int i, int j) const
194 {
195 assert(i >= 0 && i < m_iHeight && j >= 0 && j < m_iWidth);
196
197 return m_dMatrix[i*m_iWidth+j];
198 }
199
200 inline const double CMatrix::GetValue(int i, int j) const
201 {
202 assert(i >= 0 && i < m_iHeight && j >= 0 && j < m_iWidth);
203
204 return m_dMatrix[i*m_iWidth+j];
205 }
206
207 inline void CMatrix::SetValue(int i, int j, double dVal)
208 {
209 assert(i >= 0 && i < m_iHeight && j >= 0 && j < m_iWidth);
210
211 m_dMatrix[i*m_iWidth+j] = dVal;
212 }
213
214
216 {
217 memset(m_dMatrix, 0, m_iHeight*m_iWidth*sizeof(double));
218 }
219
221 {
222 CMatrix Transpose(m_iWidth, m_iHeight);
223 int i, j;
224 for (i=0; i<m_iHeight; ++i)
225 {
226 for (j=0; j<m_iWidth; ++j)
227 {
228 Transpose(j, i) = (*this)(i, j);
229 }
230 }
231 return Transpose;
232 }
233
234 inline CMatrix CMatrix::operator * (const CMatrix &RightMatrix) const
235 {
236 assert(m_iWidth == RightMatrix.m_iHeight);
237 CMatrix Multiplication(m_iHeight, RightMatrix.m_iWidth);
238 int i, j, k;
239 for (i=0; i<m_iHeight; ++i)
240 {
241 for (j=0; j<RightMatrix.m_iWidth; ++j)
242 {
243 for (k=0; k<m_iWidth; ++k)
244 {
245 Multiplication(i, j) += (*this)(i, k) * RightMatrix(k, j);
246 }
247 }
248 }
249 return Multiplication;
250 }
251
252 inline CMatrix CMatrix::operator * (double dRight) const
253 {
254 CMatrix Multiplication(m_iHeight, m_iWidth);
255 int i, j;
256 for (i=0; i<m_iHeight; ++i)
257 {
258 for (j=0; j<m_iWidth; ++j)
259 {
260 Multiplication(i, j) = (*this)(i, j) * dRight;
261 }
262 }
263 return Multiplication;
264 }
265
266 inline CMatrix CMatrix::operator + (const CMatrix &RightMatrix) const
267 {
268 assert(m_iWidth == RightMatrix.m_iWidth);
269 assert(m_iHeight == RightMatrix.m_iHeight);
270 CMatrix Addition(m_iHeight, m_iWidth);
271 int i;
272 for (i=0; i<m_iHeight*m_iWidth; ++i)
273 {
274 Addition.m_dMatrix[i] = m_dMatrix[i] + RightMatrix.m_dMatrix[i];
275 }
276 return Addition;
277 }
278
279 inline CMatrix CMatrix::operator - (const CMatrix &RightMatrix) const
280 {
281 assert(m_iWidth == RightMatrix.m_iWidth);
282 assert(m_iHeight == RightMatrix.m_iHeight);
283 CMatrix Addition(m_iHeight, m_iWidth);
284 int i;
285 for (i=0; i<m_iHeight*m_iWidth; ++i)
286 {
287 Addition.m_dMatrix[i] = m_dMatrix[i] - RightMatrix.m_dMatrix[i];
288 }
289 return Addition;
290 }
291
292
293 inline CMatrix &CMatrix::EqualsMultiple(const CMatrix &LeftMatrix, const CMatrix &RightMatrix)
294 {
295 assert(LeftMatrix.m_iWidth == RightMatrix.m_iHeight);
296 assert(&LeftMatrix != this);
297 assert(&RightMatrix != this);
298 if (m_iHeight != LeftMatrix.m_iHeight || m_iWidth != RightMatrix.m_iWidth)
299 {
300 Initialise(LeftMatrix.m_iHeight, RightMatrix.m_iWidth);
301 }
302 else
303 {
304 ZeroMatrix();
305 }
306 int i, j, k;
307 for (i=0; i<m_iHeight; ++i)
308 {
309 for (j=0; j<m_iWidth; ++j)
310 {
311 for (k=0; k<LeftMatrix.m_iWidth; ++k)
312 {
313 (*this)(i, j) += LeftMatrix(i, k) * RightMatrix(k, j);
314 }
315 }
316 }
317 return *this;
318 }
319
320 inline CMatrix &CMatrix::EqualsTransposeMultiple(const CMatrix &LeftMatrix, const CMatrix &RightMatrix)
321 {
322 assert(LeftMatrix.m_iHeight == RightMatrix.m_iHeight);
323 assert(&LeftMatrix != this);
324 assert(&RightMatrix != this);
325 if (m_iHeight != LeftMatrix.m_iWidth || m_iWidth != RightMatrix.m_iWidth)
326 {
327 Initialise(LeftMatrix.m_iWidth, RightMatrix.m_iWidth);
328 }
329 else
330 {
331 ZeroMatrix();
332 }
333 int i, j, k;
334 for (i=0; i<m_iHeight; ++i)
335 {
336 for (j=0; j<m_iWidth; ++j)
337 {
338 for (k=0; k<LeftMatrix.m_iHeight; ++k)
339 {
340 (*this)(i, j) += LeftMatrix(k, i) * RightMatrix(k, j);
341 }
342 }
343 }
344 return *this;
345 }
346
347 inline CMatrix &CMatrix::EqualsMultipleTranspose(const CMatrix &LeftMatrix, const CMatrix &RightMatrix)
348 {
349 assert(LeftMatrix.m_iWidth == RightMatrix.m_iWidth);
350 assert(&LeftMatrix != this);
351 assert(&RightMatrix != this);
352 if (m_iHeight != LeftMatrix.m_iHeight || m_iWidth != RightMatrix.m_iHeight)
353 {
354 Initialise(LeftMatrix.m_iHeight, RightMatrix.m_iHeight);
355 }
356 else
357 {
358 ZeroMatrix();
359 }
360 int i, j, k;
361 for (i=0; i<m_iHeight; ++i)
362 {
363 for (j=0; j<m_iWidth; ++j)
364 {
365 for (k=0; k<LeftMatrix.m_iWidth; ++k)
366 {
367 (*this)(i, j) += LeftMatrix(i, k) * RightMatrix(j, k);
368 }
369 }
370 }
371 return *this;
372 }
373
374 inline CMatrix &CMatrix::operator *= (double dRight)
375 {
376 int i, j;
377 for (i=0; i<m_iHeight; ++i)
378 {
379 for (j=0; j<m_iWidth; ++j)
380 {
381 (*this)(i, j) *= dRight;
382 }
383 }
384 return *this;
385 }
386
387 inline CMatrix &CMatrix::operator /= (double dRight)
388 {
389 int i, j;
390 dRight = 1.0/dRight;
391 for (i=0; i<m_iHeight; ++i)
392 {
393 for (j=0; j<m_iWidth; ++j)
394 {
395 (*this)(i, j) *= dRight;
396 }
397 }
398 return *this;
399 }
400
401 inline CMatrix &CMatrix::operator += (const CMatrix &RightMatrix)
402 {
403 if (m_iWidth != RightMatrix.m_iWidth || m_iHeight != RightMatrix.m_iHeight)
404 {
405 assert(Empty());
406 Initialise(RightMatrix.m_iHeight, RightMatrix.m_iWidth);
407 }
408 int i, j;
409 for (i=0; i<m_iHeight; ++i)
410 {
411 for (j=0; j<m_iWidth; ++j)
412 {
413 (*this)(i, j) += RightMatrix(i, j);
414 }
415 }
416 return *this;
417 }
418
419 inline CMatrix &CMatrix::operator -= (const CMatrix &RightMatrix)
420 {
421 if (m_iWidth != RightMatrix.m_iWidth || m_iHeight != RightMatrix.m_iHeight)
422 {
423 assert(Empty());
424 Initialise(RightMatrix.m_iHeight, RightMatrix.m_iWidth);
425 }
426 int i, j;
427 for (i=0; i<m_iHeight; ++i)
428 {
429 for (j=0; j<m_iWidth; ++j)
430 {
431 (*this)(i, j) -= RightMatrix(i, j);
432 }
433 }
434 return *this;
435 }
436
437 inline void CMatrix::PrintMatrix(char szMatrixName[], ostream &Output, int iWidth, bool bScientific)
438 {
439 int i, j;
440 Output << szMatrixName << endl;
441 if (bScientific)
442 Output << setiosflags(ios_base::scientific);
443 for (i=0; i<m_iHeight; ++i)
444 {
445 for (j=0; j<m_iWidth; ++j)
446 {
447 Output << setw(iWidth) << setprecision(iWidth-9) << (*this)(i, j);
448 }
449 Output << endl;
450 }
451 if (bScientific)
452 Output << resetiosflags(ios_base::scientific);
453 }
454
455 inline ostream &operator << (ostream &output, CMatrix &Matrix)
456 {
457 Matrix.PrintMatrix((char*)"", output);
458 return output;
459 }
460
461 inline void CMatrix::GetSquareRoot(CMatrix &Root) const
462 {
463 assert(m_iWidth == m_iHeight);
464
465 int i;
466 const int n = m_iWidth;
467
468 CMatrix EigenValues;
469 CMatrix EigenVectors;
470 CMatrix EigenVectorsInverse;
471 GetEigen(EigenVectors, EigenValues);
472 EigenVectors.GetInverse(EigenVectorsInverse);
473 CMatrix A(n, n);
474 for (i=0; i<n; ++i)
475 {
476 assert(EigenValues(0, i) >= 0);
477 A(i, i) = sqrt(EigenValues(0, i));
478 }
479 // CMatrix A = EigenVectorsInverse * (*this) * EigenVectors;
480 // for (i=0; i<n; ++i)
481 // {
482 // A(i, i) = sqrt(A(i, i));
483 // }
484 CMatrix Temp;
485 Temp.EqualsMultiple(EigenVectors, A);
486 Root.EqualsMultiple(Temp, EigenVectorsInverse);
487 }
488
489 inline double CMatrix::GetDeterminant() const
490 {
491 assert(m_iWidth == m_iHeight);
492
493 const int n = m_iWidth; // == m_iHeight
494 if (n == 1)
495 return (*this)(0, 0);
496 if (n == 2)
497 {
498 return (*this)(0, 0) * (*this)(1, 1) - (*this)(1, 0) * (*this)(0, 1);
499 }
500 if (n == 3)
501 {
502 double d1, d2, d3;
503 d1 = (*this)(1, 1) * (*this)(2, 2) - (*this)(2, 1) * (*this)(1, 2);
504 d2 = (*this)(1, 2) * (*this)(2, 0) - (*this)(2, 2) * (*this)(1, 0);
505 d3 = (*this)(1, 0) * (*this)(2, 1) - (*this)(2, 0) * (*this)(1, 1);
506 return (*this)(0, 0) * d1 + (*this)(0, 1) * d2 + (*this)(0, 2) * d3;
507 }
508
509 // Don't care about the inverse but it returns the determinant
510 CMatrix Inverse;
511 return GetInverse(Inverse);
512
513/* int i, j=0;
514 double det = 0;
515 CMatrix SubMatrix;
516 for (i=0; i<n; ++i)
517 {
518 GetSubMatrix(SubMatrix, i, j);
519 if ((i+j)%2 == 0)
520 det += (*this)(i, j)*SubMatrix.GetDeterminant();
521 else
522 det -= (*this)(i, j)*SubMatrix.GetDeterminant();
523 }
524 return det;*/
525 }
526
527 inline void CMatrix::Identity()
528 {
529 assert(m_iWidth == m_iHeight);
530
531 const int n = m_iWidth; // == m_iHeight
532
533 int i, j;
534
535 for (i=0; i<n; ++i)
536 {
537 for (j=0; j<n; ++j)
538 {
539 (*this)(i, j) = (i == j);
540 }
541 }
542 }
543
544 inline double CMatrix::GetInverse(CMatrix &Inverse) const
545 {
546 assert(m_iWidth == m_iHeight);
547
548 const int n = m_iWidth; // == m_iHeight
549
550 if (Inverse.m_iHeight != n || Inverse.m_iWidth != n)
551 Inverse.Initialise(n, n);
552
553 if (n == 2)
554 {
555 double dCoef;
556 double dDeterminant = GetDeterminant();
557
558 assert(dDeterminant);
559
560 dCoef = 1.0/dDeterminant;
561
562 Inverse(0, 0) = dCoef*(*this)(1, 1);
563 Inverse(1, 1) = dCoef*(*this)(0, 0);
564 Inverse(1, 0) = -dCoef*(*this)(1, 0);
565 Inverse(0, 1) = -dCoef*(*this)(0, 1);
566
567 return dDeterminant;
568 }
569 if (n == 3)
570 {
571 double dCoef;
572 double dDeterminant = GetDeterminant();
573
574 assert(dDeterminant);
575
576 dCoef = 1.0/dDeterminant;
577
578 int i, j;
579
580 static CMatrix SubMatrix(2, 2);
581
582 for (i=0; i<3; ++i)
583 {
584 for (j=0; j<3; ++j)
585 {
586 SubMatrix(0, 0) = (*this)((i+1)%3, (j+1)%3);
587 SubMatrix(1, 0) = (*this)((i+2)%3, (j+1)%3);
588 SubMatrix(0, 1) = (*this)((i+1)%3, (j+2)%3);
589 SubMatrix(1, 1) = (*this)((i+2)%3, (j+2)%3);
590
591 Inverse(j, i) = dCoef*SubMatrix.GetDeterminant();
592 }
593 }
594
595 return dDeterminant;
596 }
597
598 CMatrix A = *this;
599
600 int i, j, k;
601 CMatrix b(n,n); // Scale factor and work array
602 vector<double> scale(n);
603 vector<int> index(n);
604
605 //* Matrix b is initialized to the identity matrix
606 b.Identity();
607
608 //* Set scale factor, scale(i) = max( |a(i,j)| ), for each row
609 for( i=0; i<n; i++ )
610 {
611 index[i] = i; // Initialize row index list
612 double scalemax = 0.;
613 for( j=0; j<n; j++ )
614 scalemax = (scalemax > fabs(A(i,j))) ? scalemax : fabs(A(i,j));
615 scale[i] = scalemax;
616 }
617
618 //* Loop over rows k = 1, ..., (n-1)
619 int signDet = 1;
620 for( k=0; k<n-1; k++ )
621 {
622 //* Select pivot row from max( |a(j,k)/s(j)| )
623 double ratiomax = 0.0;
624 int jPivot = k;
625 for( i=k; i<n; i++ )
626 {
627 double ratio = fabs(A(index[i],k))/scale[index[i]];
628 if( ratio > ratiomax )
629 {
630 jPivot=i;
631 ratiomax = ratio;
632 }
633 }
634 //* Perform pivoting using row index list
635 int indexJ = index[k];
636 if( jPivot != k )
637 { // Pivot
638 indexJ = index[jPivot];
639 index[jPivot] = index[k]; // Swap index jPivot and k
640 index[k] = indexJ;
641 signDet *= -1; // Flip sign of determinant
642 }
643 //* Perform forward elimination
644 for( i=k+1; i<n; i++ )
645 {
646 double coeff = A(index[i],k)/A(indexJ,k);
647 for( j=k+1; j<n; j++ )
648 A(index[i],j) -= coeff*A(indexJ,j);
649 A(index[i],k) = coeff;
650 for( j=0; j<n; j++ )
651 b(index[i],j) -= A(index[i],k)*b(indexJ,j);
652 }
653 }
654 //* Compute determinant as product of diagonal elements
655 double determ = signDet; // Sign of determinant
656 for( i=0; i<n; i++ )
657 determ *= A(index[i],i);
658
659 //* Perform backsubstitution
660 for( k=0; k<n; k++ )
661 {
662 Inverse(n-1,k) = b(index[n-1],k)/A(index[n-1],n-1);
663 for( i=n-2; i>=0; i--)
664 {
665 double sum = b(index[i],k);
666 for( j=i; j<n; j++ )
667 sum -= A(index[i],j)*Inverse(j,k);
668 Inverse(i,k) = sum/A(index[i],i);
669 }
670 }
671
672 return determ;
673
674// return GetInverseSlow(Inverse);
675 }
676
677 inline double CMatrix::GetInverseSlow(CMatrix &Inverse) const
678 {
679 assert(m_iWidth == m_iHeight);
680
681 const int n = m_iWidth; // == m_iHeight
682
683 if (Inverse.m_iHeight != n || Inverse.m_iWidth != n)
684 Inverse.Initialise(n, n);
685
686 double dCoef;
687 double dDeterminant = GetDeterminant();
688
689 assert(dDeterminant);
690
691 dCoef = 1.0/dDeterminant;
692
693 int i, j;
694
695 CMatrix SubMatrix;
696
697 for (i=0; i<n; ++i)
698 {
699 for (j=0; j<n; ++j)
700 {
701 GetSubMatrix(SubMatrix, i, j);
702 Inverse(j, i) = dCoef*SubMatrix.GetDeterminant();
703 if ((i+j)%2)
704 Inverse(j, i) *= -1;
705 }
706 }
707
708 return dDeterminant;
709 }
710
711 inline void CMatrix::SwapRows(int iRow1, int iRow2)
712 {
713 assert(iRow1 >= 0 && iRow1 < m_iHeight);
714 assert(iRow2 >= 0 && iRow2 < m_iHeight);
715 int i;
716 double dTemp;
717 for (i=0; i<m_iWidth; ++i)
718 {
719 dTemp = (*this)(iRow1, i);
720 (*this)(iRow1, i) = (*this)(iRow2, i);
721 (*this)(iRow2, i) = dTemp;
722 }
723 // PrintMatrix();
724 // cout << endl;
725 }
726
727 inline void CMatrix::SwapColumns(int iColumn1, int iColumn2)
728 {
729 assert(iColumn1 >= 0 && iColumn1 < m_iWidth);
730 assert(iColumn2 >= 0 && iColumn2 < m_iWidth);
731 int i;
732 double dTemp;
733 for (i=0; i<m_iHeight; ++i)
734 {
735 dTemp = (*this)(i, iColumn1);
736 (*this)(i, iColumn1) = (*this)(i, iColumn2);
737 (*this)(i, iColumn2) = dTemp;
738 }
739 // PrintMatrix();
740 // cout << endl;
741 }
742
743 inline void CMatrix::DivideRow(int iRow, double dDivisor)
744 {
745 assert(iRow >= 0 && iRow < m_iHeight);
746 int i;
747 for (i=0; i<m_iWidth; ++i)
748 {
749 (*this)(iRow, i) /= dDivisor;
750 }
751 // PrintMatrix();
752 // cout << endl;
753 }
754
755 inline void CMatrix::DivideColumn(int iColumn, double dDivisor)
756 {
757 assert(iColumn >= 0 && iColumn < m_iWidth);
758 int i;
759 for (i=0; i<m_iHeight; ++i)
760 {
761 (*this)(i, iColumn) /= dDivisor;
762 }
763 // PrintMatrix();
764 // cout << endl;
765 }
766
767 inline void CMatrix::SubtractRow(int iRow1, int iRow2, double dScale)
768 {
769 assert(iRow1 >= 0 && iRow1 < m_iHeight);
770 assert(iRow2 >= 0 && iRow2 < m_iHeight);
771 int i;
772 for (i=0; i<m_iWidth; ++i)
773 {
774 (*this)(iRow1, i) -= (*this)(iRow2, i) * dScale;
775 }
776 // PrintMatrix();
777 // cout << endl;
778 }
779
780 inline void CMatrix::SubtractColumn(int iColumn1, int iColumn2, double dScale)
781 {
782 assert(iColumn1 >= 0 && iColumn1 < m_iWidth);
783 assert(iColumn2 >= 0 && iColumn2 < m_iWidth);
784 int i;
785 for (i=0; i<m_iHeight; ++i)
786 {
787 (*this)(i, iColumn1) -= (*this)(i, iColumn2) * dScale;
788 }
789 // PrintMatrix();
790 // cout << endl;
791 }
792
793 inline CMatrix &CMatrix::GetSubMatrix(CMatrix &SubMatrix, int iRow, int iColumn) const
794 {
795 if (SubMatrix.m_iWidth != m_iWidth-1 && SubMatrix.m_iHeight != m_iHeight-1)
796 SubMatrix.Initialise(m_iHeight-1, m_iWidth-1);
797
798 int i, j, k, l;
799
800 for (i=0, k=0; i<m_iWidth; ++i)
801 {
802 if (i == iColumn)
803 continue;
804 for (j=0, l=0; j<m_iHeight; ++j)
805 {
806 if (j == iRow)
807 continue;
808 SubMatrix(l, k) = (*this)(j, i);
809 ++l;
810 }
811 ++k;
812 }
813
814 return SubMatrix;
815 }
816
818 {
819 assert(m_iWidth == m_iHeight);
820 CMatrix PSquared, PInverse;
821 PSquared.EqualsTransposeMultiple(*this, *this);
822 PSquared.GetSquareRoot(P);
823 P.GetInverse(PInverse);
824 U.EqualsMultiple(*this, PInverse);
825 }
826
827 inline void CMatrix::GetEigen(CMatrix &EigenVectors, CMatrix &EigenValues) const
828 {
829 assert(m_iWidth == m_iHeight);
830
831 const int n = m_iWidth;
832
833 // WORKS ONLY FOR SYMETRIC MATRICES
834 bool bSymetric = true;
835 int i, j;
836 for (i=0; i<n && bSymetric; ++i)
837 {
838 for (j=i+1; j<n && bSymetric; ++j)
839 {
840 if (fabs((*this)(i, j) - (*this)(j, i)) > 1e-6)
841 bSymetric = false;
842 }
843 }
844 assert(bSymetric);
845 if (bSymetric)
846 {
847 if (EigenValues.m_iHeight != 1 || EigenValues.m_iWidth != n)
848 EigenValues.Initialise(1, n);
849
850 double *e = new double[n];
851
852 int i, j, k, l;
853
854 EigenVectors = (*this);
855
856 // This is derived from the Algol procedures tred2 by
857 // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
858 // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
859 // Fortran subroutine in EISPACK.
860 for (j = 0; j < n; j++)
861 {
862 EigenValues(0, j) = EigenVectors(n - 1, j);
863 }
864
865 // Householder reduction to tridiagonal form.
866
867 for (i = n - 1; i > 0; i--)
868 {
869 // Scale to avoid under/overflow.
870
871 double scale = 0.0;
872 double h = 0.0;
873 for (k = 0; k < i; k++)
874 {
875 scale = scale + fabs(EigenValues(0, k));
876 }
877 if (scale == 0.0)
878 {
879 e[i] = EigenValues(0, i - 1);
880 for (j = 0; j < i; j++)
881 {
882 EigenValues(0, j) = EigenVectors(i - 1, j);
883 EigenVectors(i, j) = 0.0;
884 EigenVectors(j, i) = 0.0;
885 }
886 }
887 else
888 {
889 // Generate Householder vector.
890
891 for (k = 0; k < i; k++)
892 {
893 EigenValues(0, k) /= scale;
894 h += EigenValues(0, k) * EigenValues(0, k);
895 }
896 double f = EigenValues(0, i - 1);
897 double g = sqrt(h);
898 if (f > 0)
899 {
900 g = - g;
901 }
902 e[i] = scale * g;
903 h = h - f * g;
904 EigenValues(0, i - 1) = f - g;
905 for (j = 0; j < i; j++)
906 {
907 e[j] = 0.0;
908 }
909
910 // Apply similarity transformation to remaining columns.
911
912 for (j = 0; j < i; j++)
913 {
914 f = EigenValues(0, j);
915 EigenVectors(j, i) = f;
916 g = e[j] + EigenVectors(j, j) * f;
917 for (k = j + 1; k <= i - 1; k++)
918 {
919 g += EigenVectors(k, j) * EigenValues(0, k);
920 e[k] += EigenVectors(k, j) * f;
921 }
922 e[j] = g;
923 }
924 f = 0.0;
925 for (j = 0; j < i; j++)
926 {
927 e[j] /= h;
928 f += e[j] * EigenValues(0, j);
929 }
930 double hh = f / (h + h);
931 for (j = 0; j < i; j++)
932 {
933 e[j] -= hh * EigenValues(0, j);
934 }
935 for (j = 0; j < i; j++)
936 {
937 f = EigenValues(0, j);
938 g = e[j];
939 for (k = j; k <= i - 1; k++)
940 {
941 EigenVectors(k, j) -= (f * e[k] + g * EigenValues(0, k));
942 }
943 EigenValues(0, j) = EigenVectors(i - 1, j);
944 EigenVectors(i, j) = 0.0;
945 }
946 }
947 EigenValues(0, i) = h;
948 }
949
950 // Accumulate transformations.
951
952 for (i = 0; i < n - 1; i++)
953 {
954 EigenVectors(n - 1, i) = EigenVectors(i, i);
955 EigenVectors(i, i) = 1.0;
956 double h = EigenValues(0, i + 1);
957 if (h != 0.0)
958 {
959 for (k = 0; k <= i; k++)
960 {
961 EigenValues(0, k) = EigenVectors(k, i + 1) / h;
962 }
963 for (j = 0; j <= i; j++)
964 {
965 double g = 0.0;
966 for (k = 0; k <= i; k++)
967 {
968 g += EigenVectors(k, i + 1) * EigenVectors(k, j);
969 }
970 for (k = 0; k <= i; k++)
971 {
972 EigenVectors(k, j) -= g * EigenValues(0, k);
973 }
974 }
975 }
976 for (k = 0; k <= i; k++)
977 {
978 EigenVectors(k, i + 1) = 0.0;
979 }
980 }
981 for (j = 0; j < n; j++)
982 {
983 EigenValues(0, j) = EigenVectors(n - 1, j);
984 EigenVectors(n - 1, j) = 0.0;
985 }
986 EigenVectors(n - 1, n - 1) = 1.0;
987 e[0] = 0.0;
988
989 for (i = 1; i < n; i++)
990 {
991 e[i - 1] = e[i];
992 }
993 e[n - 1] = 0.0;
994
995 double f = 0.0;
996 double tst1 = 0.0;
997 double eps = 2E-52;
998 for (l = 0; l < n; l++)
999 {
1000 // Find small subdiagonal element
1001 if (fabs(EigenValues(0, l)) + fabs(e[l]) > tst1)
1002 tst1 = fabs(EigenValues(0, l)) + fabs(e[l]);
1003
1004 int m = l;
1005 while (m < n)
1006 {
1007 if (fabs(e[m]) <= eps * tst1)
1008 {
1009 break;
1010 }
1011 m++;
1012 }
1013
1014 // If m == l, EigenValues(0, l) is an eigenvalue,
1015 // otherwise, iterate.
1016
1017 if (m > l)
1018 {
1019 int iter = 0;
1020 do
1021 {
1022 iter = iter + 1; // (Could check iteration count here.)
1023
1024 // Compute implicit shift
1025
1026 double g = EigenValues(0, l);
1027 double p = (EigenValues(0, l + 1) - g) / (2.0 * e[l]);
1028 // double r = Maths.Hypot(p, 1.0);
1029 double r = sqrt(p*p+1);
1030 if (p < 0)
1031 {
1032 r = - r;
1033 }
1034 EigenValues(0, l) = e[l] / (p + r);
1035 EigenValues(0, l + 1) = e[l] * (p + r);
1036 double dl1 = EigenValues(0, l + 1);
1037 double h = g - EigenValues(0, l);
1038 for (i = l + 2; i < n; i++)
1039 {
1040 EigenValues(0, i) -= h;
1041 }
1042 f = f + h;
1043
1044 // Implicit QL transformation.
1045
1046 p = EigenValues(0, m);
1047 double c = 1.0;
1048 double c2 = c;
1049 double c3 = c;
1050 double el1 = e[l + 1];
1051 double s = 0.0;
1052 double s2 = 0.0;
1053 for (i = m - 1; i >= l; i--)
1054 {
1055 c3 = c2;
1056 c2 = c;
1057 s2 = s;
1058 g = c * e[i];
1059 h = c * p;
1060 // r = Maths.Hypot(p, e[i]);
1061 r = sqrt(p*p+e[i]*e[i]);
1062 e[i + 1] = s * r;
1063 s = e[i] / r;
1064 c = p / r;
1065 p = c * EigenValues(0, i) - s * g;
1066 EigenValues(0, i + 1) = h + s * (c * g + s * EigenValues(0, i));
1067
1068 // Accumulate transformation.
1069
1070 for (k = 0; k < n; k++)
1071 {
1072 h = EigenVectors(k, i + 1);
1073 EigenVectors(k, i + 1) = s * EigenVectors(k, i) + c * h;
1074 EigenVectors(k, i) = c * EigenVectors(k, i) - s * h;
1075 }
1076 }
1077 p = (- s) * s2 * c3 * el1 * e[l] / dl1;
1078 e[l] = s * p;
1079 EigenValues(0, l) = c * p;
1080
1081 // Check for convergence.
1082 }
1083 while (fabs(e[l]) > eps * tst1);
1084 }
1085 EigenValues(0, l) = EigenValues(0, l) + f;
1086 e[l] = 0.0;
1087 }
1088
1089 // Sort eigenvalues and corresponding vectors.
1090
1091 for (i = 0; i < n - 1; i++)
1092 {
1093 int k = i;
1094 double p = EigenValues(0, i);
1095 for (j = i + 1; j < n; j++)
1096 {
1097 if (EigenValues(0, j) < p)
1098 {
1099 k = j;
1100 p = EigenValues(0, j);
1101 }
1102 }
1103 if (k != i)
1104 {
1105 EigenValues(0, k) = EigenValues(0, i);
1106 EigenValues(0, i) = p;
1107 for (j = 0; j < n; j++)
1108 {
1109 p = EigenVectors(j, i);
1110 EigenVectors(j, i) = EigenVectors(j, k);
1111 EigenVectors(j, k) = p;
1112 }
1113 }
1114 }
1115 delete [] e;
1116 }
1117 }
1118
1119 inline void CMatrix::SetSubMatrix(TexGen::CMatrix &SubMatrix, int iRow, int iColumn)
1120 {
1121 if ( (iColumn + SubMatrix.m_iWidth) > m_iWidth || (iRow + SubMatrix.m_iHeight) > m_iHeight )
1122 return;
1123 for ( int i = 0; i < SubMatrix.m_iHeight; ++i )
1124 {
1125 for ( int j = 0; j < SubMatrix.m_iWidth; ++j )
1126 {
1127 (*this).SetValue( iRow+i, iColumn+j, SubMatrix.GetValue( i, j ) );
1128 }
1129 }
1130 }
1131}; // namespace TexGen
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
#define NULL
Definition: ShinyConfig.h:50
Class to represent a matrix and perform various operations on it.
Definition: Matrix.h:33
void Initialise(int iHeight, int iWidth)
Definition: Matrix.h:144
CMatrix & operator=(const CMatrix &RightMatrix)
Definition: Matrix.h:134
CMatrix & operator+=(const CMatrix &RightMatrix)
Definition: Matrix.h:401
void Identity()
Definition: Matrix.h:527
void SubtractRow(int iRow1, int iRow2, double dScale)
Definition: Matrix.h:767
CMatrix operator*(const CMatrix &RightMatrix) const
Definition: Matrix.h:234
void SetSubMatrix(CMatrix &SubMatrix, int iRow, int iColumn)
Definition: Matrix.h:1119
CMatrix & EqualsMultipleTranspose(const CMatrix &LeftMatrix, const CMatrix &RightMatrix)
This function multiplies the transpose of the left matrix with the right matrix.
Definition: Matrix.h:347
void SwapRows(int iRow1, int iRow2)
Definition: Matrix.h:711
double GetInverse(CMatrix &Inverse) const
Definition: Matrix.h:544
void DivideColumn(int iColumn, double dDivisor)
Definition: Matrix.h:755
void SwapColumns(int iColumn1, int iColumn2)
Definition: Matrix.h:727
void PrintMatrix(char szMatrixName[], ostream &Output=cout, int iWidth=16, bool bScientific=true)
Definition: Matrix.h:437
CMatrix & GetSubMatrix(CMatrix &SubMatrix, int iRow, int iColumn) const
Definition: Matrix.h:793
double & operator()(int i, int j)
Definition: Matrix.h:186
CMatrix GetTranspose()
Definition: Matrix.h:220
double GetDeterminant() const
Definition: Matrix.h:489
void SubtractColumn(int iColumn1, int iColumn2, double dScale)
Definition: Matrix.h:780
int GetHeight() const
Definition: Matrix.h:176
const double GetValue(int i, int j) const
Definition: Matrix.h:200
CMatrix operator-(const CMatrix &RightMatrix) const
Definition: Matrix.h:279
CMatrix operator+(const CMatrix &RightMatrix) const
Definition: Matrix.h:266
void DivideRow(int iRow, double dDivisor)
Definition: Matrix.h:743
double GetInverseSlow(CMatrix &Inverse) const
Definition: Matrix.h:677
CMatrix & operator*=(double dRight)
Definition: Matrix.h:374
CMatrix & EqualsTransposeMultiple(const CMatrix &LeftMatrix, const CMatrix &RightMatrix)
This function multiplies the transpose of the left matrix with the right matrix.
Definition: Matrix.h:320
CMatrix & operator-=(const CMatrix &RightMatrix)
Definition: Matrix.h:419
void ZeroMatrix()
Definition: Matrix.h:215
void GetSquareRoot(CMatrix &Root) const
Definition: Matrix.h:461
void SetValue(int i, int j, double dVal)
Definition: Matrix.h:207
int m_iWidth
Definition: Matrix.h:99
void InitialiseIdentity(int iSize)
Definition: Matrix.h:155
~CMatrix(void)
Definition: Matrix.h:128
void GetEigen(CMatrix &EigenVectors, CMatrix &EigenValues) const
Definition: Matrix.h:827
int GetWidth() const
Definition: Matrix.h:181
bool Empty() const
Definition: Matrix.h:171
CMatrix & EqualsMultiple(const CMatrix &LeftMatrix, const CMatrix &RightMatrix)
This function multiplies the left matrix with the right matrix.
Definition: Matrix.h:293
void GetPolarDecomposition(CMatrix &U, CMatrix &P) const
Definition: Matrix.h:817
double * m_dMatrix
Definition: Matrix.h:101
CMatrix & operator/=(double dRight)
Definition: Matrix.h:387
Namespace containing a series of customised math operations not found in the standard c++ library.
ostream & operator<<(ostream &output, CMatrix &Matrix)
Definition: Matrix.h:455