ScummVM API documentation
dgGeneralMatrix.h
1 /* Copyright (c) <2003-2011> <Julio Jerez, Newton Game Dynamics>
2 *
3 * This software is provided 'as-is', without any express or implied
4 * warranty. In no event will the authors be held liable for any damages
5 * arising from the use of this software.
6 *
7 * Permission is granted to anyone to use this software for any purpose,
8 * including commercial applications, and to alter it and redistribute it
9 * freely, subject to the following restrictions:
10 *
11 * 1. The origin of this software must not be misrepresented; you must not
12 * claim that you wrote the original software. If you use this software
13 * in a product, an acknowledgment in the product documentation would be
14 * appreciated but is not required.
15 *
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 *
19 * 3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #ifndef __dgGeneralMatrix__
23 #define __dgGeneralMatrix__
24 
25 #include "dgStdafx.h"
26 #include "dgDebug.h"
27 #include "dgGeneralVector.h"
28 
29 
30 
31 
32 template <class T> dgInt32 dgGeneralMatrixCalcBufferSizeInBytes(dgInt32 row, dgInt32 column) {
33  dgInt32 columnPad;
34  columnPad = ((column * sizeof(T) + 0x0f) & -0x0f) / sizeof(T);
35  return row * columnPad * sizeof(T) + row * sizeof(dgGeneralVector<T>);
36 }
37 
38 
39 template<class T>
41 public:
42  dgGeneralMatrix(dgInt32 row, dgInt32 column);
44  dgGeneralMatrix(const dgGeneralMatrix<T> &src, T *elemBuffer);
45  dgGeneralMatrix(dgInt32 row, dgInt32 column, T *elemBuffer);
46  ~dgGeneralMatrix();
47 
48  dgGeneralVector<T> &operator[](dgInt32 i);
49  const dgGeneralVector<T> &operator[](dgInt32 i) const;
50 
51  dgInt32 GetRowCount() const;
52  dgInt32 GetColCount() const;
53 
54  void Clear(T val);
55  void Identity();
56 
57  void SwapRows(dgInt32 i, dgInt32 j);
58  void SwapColumns(dgInt32 i, dgInt32 j);
59 
60 // dgGeneralMatrix Transpose ();
61 // void Inverse (dgGeneralMatrix& inverseOut);
62  void GaussianPivotStep(dgInt32 srcRow, dgInt32 pivotRow, dgInt32 pivotCol, T tol = T(1.0e-6f));
63 
64 
65  // calculate out = V * A;
66  void VectorTimeMatrix(const dgGeneralVector<T> &v, dgGeneralVector<T> &out);
67 
68  // calculate out = A * transpose (V);
69  void MatrixTimeVectorTranspose(const dgGeneralVector<T> &v, dgGeneralVector<T> &out);
70 
71 
72  // calculate M = A * B;
73  void MatrixTimeMatrix(const dgGeneralMatrix<T> &A, const dgGeneralMatrix<T> &B);
74 
75  // calculate M = A * transpose (B);
76  void MatrixTimeMatrixTranspose(const dgGeneralMatrix<T> &A, const dgGeneralMatrix<T> &Bt);
77 
78  bool Solve(dgGeneralVector<T> &b, T tol = T(0.0f));
79 
80  bool CholeskyDecomposition();
81  bool TestPSD() const;
82  bool TestSymetry() const;
83 
84 
85  void Trace() const;
86 
87 
88 protected:
89  bool m_ownMemory;
90  dgInt32 m_rowCount;
91  dgInt32 m_colCount;
92  dgGeneralVector<T> *m_rows;
93 
94 private:
95  T *m_buffer;
96 };
97 
98 
99 // ***********************************************************************************************
100 //
101 // LinearSystem
102 //
103 // ***********************************************************************************************
104 template<class T>
105 dgGeneralMatrix<T>::dgGeneralMatrix(dgInt32 row, dgInt32 column) {
106  dgInt32 i;
107  dgInt32 columnPad;
108  NEWTON_ASSERT(row > 0);
109  NEWTON_ASSERT(column > 0);
110 
111  m_rowCount = row;
112  m_colCount = column;
113  m_ownMemory = true;
114 
115 
116  columnPad = ((column * sizeof(T) + 0x0f) & -0x0f) / sizeof(T);
117  m_buffer = new T [row * columnPad];
118 
119  m_rows = new dgGeneralVector<T>[row];
120  for (i = 0; i < row; i ++) {
121  m_rows[i] = dgGeneralVector<T> (column, &m_buffer[i * columnPad]);
122  }
123 }
124 
125 
126 template<class T>
128  dgInt32 i;
129  dgInt32 columnPad;
130 
131  m_ownMemory = true;
132  m_rowCount = src.m_rowCount;
133  m_colCount = src.m_colCount;
134 
135  columnPad = ((m_colCount * sizeof(T) + 0x0f) & -0x0f) / sizeof(T);
136  m_buffer = new T [m_rowCount * columnPad];
137  m_rows = new dgGeneralVector<T>[m_rowCount];
138 
139  for (i = 0; i < m_rowCount; i ++) {
140  m_rows[i] = dgGeneralVector<T> (src[i], &m_buffer[i * columnPad]);
141  }
142 }
143 
144 template<class T>
146  dgInt32 row,
147  dgInt32 column,
148  T *elemBuffer) {
149  dgInt32 i;
150  dgInt32 columnPad;
151 
152  m_ownMemory = false;
153  m_rowCount = row;
154  m_colCount = column;
155 
156 
157  NEWTON_ASSERT((((dgUnsigned32) elemBuffer) & 0x0f) == 0);
158 
159  m_buffer = elemBuffer;
160  columnPad = ((m_colCount * sizeof(T) + 0x0f) & -0x0f) / sizeof(T);
161  m_rows = (dgGeneralVector<T> *) &elemBuffer[m_rowCount * columnPad];
162  for (i = 0; i < row; i ++) {
163  m_rows[i] = dgGeneralVector<T> (column, &m_buffer[i * columnPad]);
164  }
165 }
166 
167 
168 template<class T>
170  const dgGeneralMatrix<T> &src,
171  T *elemBuffer) {
172  dgInt32 i;
173  dgInt32 columnPad;
174 
175  m_ownMemory = false;
176  m_rowCount = src.m_rowCount;
177  m_colCount = src.m_colCount;
178 
179  NEWTON_ASSERT((((dgUnsigned32) elemBuffer) & 0x0f) == 0);
180  m_buffer = elemBuffer;
181 
182  columnPad = ((m_colCount * sizeof(T) + 0x0f) & -0x0f) / sizeof(T);
183  m_rows = (dgGeneralVector<T> *) &elemBuffer[m_rowCount * columnPad];
184  for (i = 0; i < m_rowCount; i ++) {
185  m_rows[i] = dgGeneralVector<T> (src[i], &m_buffer[i * columnPad]);
186  }
187 }
188 
189 
190 
191 template<class T>
193  if (m_ownMemory) {
194  delete[] m_rows;
195  delete[] m_buffer;
196  }
197 }
198 
199 
200 template<class T>
201 dgInt32 dgGeneralMatrix<T>::GetRowCount() const {
202  return m_rowCount;
203 }
204 
205 template<class T>
206 dgInt32 dgGeneralMatrix<T>::GetColCount() const {
207  return m_colCount;
208 }
209 
210 
211 template<class T>
212 void dgGeneralMatrix<T>::Trace() const {
213  dgInt32 i;
214 
215  for (i = 0; i < m_rowCount; i ++) {
216  m_rows[i].Trace();
217  }
218 }
219 
220 
221 
222 template<class T>
224  NEWTON_ASSERT(i < m_rowCount);
225  NEWTON_ASSERT(i >= 0);
226  return m_rows[i];
227 }
228 
229 template<class T>
230 const dgGeneralVector<T> &dgGeneralMatrix<T>::operator[](dgInt32 i) const {
231  NEWTON_ASSERT(i < m_rowCount);
232  NEWTON_ASSERT(i >= 0);
233  return m_rows[i];
234 }
235 
236 template<class T>
237 void dgGeneralMatrix<T>::Clear(T val) {
238  dgInt32 i;
239  for (i = 0; i < m_rowCount; i ++) {
240  m_rows[i].Clear(val);
241  }
242 }
243 
244 template<class T>
246  dgInt32 i;
247 
248  for (i = 0; i < m_rowCount; i ++) {
249  m_rows[i].Clear(T(0.0f));
250  m_rows[i][i] = T(1.0f);
251  }
252 }
253 
254 
255 //template<class T>
256 //void dgGeneralMatrix<T>::Transpose ()
257 //{
258 // dgInt32 i;
259 // dgInt32 j;
260 //
261 // NEWTON_ASSERT (m_rowCount ==
262 // dgGeneralMatrix<T>& me = *this;
263 // for (i = 0; i < m_rowCount; i ++) {
264 // for (j = i + 1; j < m_rowCount; j ++) {
265 // T tmp (me[i][j]);
266 // me[i][j] = me[j][i];
267 // me[j][i] = tmp;
268 //
269 // #ifdef DG_COUNT_FLOAT_OPS
270 // dgGeneralVector<T>::m_memoryWrite += 2;
271 // #endif
272 // }
273 // }
274 //}
275 
276 
277 template<class T>
279  dgInt32 srcRow,
280  dgInt32 pivotRow,
281  dgInt32 pivotCol,
282  T tol) {
283  dgGeneralMatrix<T> &me = *this;
284 
285  T num(me[pivotRow][pivotCol]);
286  if (T(dgAbsf(num)) > tol) {
287  T den(me[srcRow][pivotCol]);
288  NEWTON_ASSERT(T(dgAbsf(den)) > T(0.0f));
289 
290 #ifdef DG_COUNT_FLOAT_OPS
292 #endif
293 
294  den = - num / den;
295  me[pivotRow].LinearCombine(den, me[srcRow], me[pivotRow]);
296  }
297 }
298 
299 
300 //template<class T>
301 //void dgGeneralMatrix<T>::Inverse (dgGeneralMatrix& inverseOut)
302 //{
303 // NEWTON_ASSERT (m_colCount == m_rowCount);
304 //}
305 
306 
307 template<class T>
309  dgInt32 i;
310  dgInt32 j;
311  T acc;
312  T *outMem;
313  const T *inMem;
314 
315  NEWTON_ASSERT(&v != &out);
316  NEWTON_ASSERT(m_rowCount == v.m_colCount);
317  NEWTON_ASSERT(m_colCount == out.m_colCount);
318 
319  inMem = &v[0];
320  outMem = &out[0];
321  const dgGeneralMatrix<T> &me = *this;
322  for (i = 0; i < m_colCount; i ++) {
323  acc = T(0.0f);
324  for (j = 0; j < m_rowCount; j ++) {
325  acc = acc + inMem[j] * me[j][i];
326 
327 #ifdef DG_COUNT_FLOAT_OPS
329 #endif
330  }
331  outMem[i] = acc;
332 #ifdef DG_COUNT_FLOAT_OPS
334 #endif
335  }
336 }
337 
338 
339 template<class T>
341  dgInt32 i;
342 
343  NEWTON_ASSERT(&v != &out);
344  NEWTON_ASSERT(m_rowCount == out.m_colCount);
345  NEWTON_ASSERT(m_colCount == v.m_colCount);
346 
347  for (i = 0; i < m_rowCount; i ++) {
348  out[i] = v.DotProduct(m_rows[i]);
349  }
350 }
351 
352 template<class T>
354  dgInt32 i;
355  dgInt32 j;
356  dgInt32 k;
357  dgInt32 count;
358  T *out;
359  T *rowA;
360 
361  NEWTON_ASSERT(m_rowCount == A.m_rowCount);
362  NEWTON_ASSERT(m_colCount == B.m_colCount);
363  NEWTON_ASSERT(A.m_colCount == B.m_rowCount);
364 
365  NEWTON_ASSERT(this != &A);
366 
367  count = A.m_colCount;
368  for (i = 0; i < m_rowCount; i ++) {
369  out = &m_rows[i][0];
370  rowA = &A.m_rows[i][0];
371  for (j = 0; j < m_colCount; j ++) {
372  T acc(0.0f);
373  for (k = 0; k < count; k ++) {
374  acc = acc + rowA[k] * B.m_rows[k][j];
375 
376 #ifdef DG_COUNT_FLOAT_OPS
378 #endif
379  }
380  out[j] = acc;
381 
382 #ifdef DG_COUNT_FLOAT_OPS
384 #endif
385  }
386  }
387 }
388 
389 
390 template<class T>
392  dgInt32 i;
393  dgInt32 j;
394  dgInt32 k;
395  dgInt32 count;
396  T *out;
397  T *rowA;
398  T *rowB;
399 
400  NEWTON_ASSERT(m_rowCount == A.m_rowCount);
401  NEWTON_ASSERT(m_colCount == Bt.m_rowCount);
402  NEWTON_ASSERT(A.m_colCount == Bt.m_colCount);
403 
404  NEWTON_ASSERT(this != &A);
405  NEWTON_ASSERT(this != &Bt);
406 
407  count = A.m_colCount;
408  for (i = 0; i < m_rowCount; i ++) {
409  out = &m_rows[i][0];
410  rowA = &A.m_rows[i][0];
411  for (j = 0; j < m_colCount; j ++) {
412  T acc(0.0f);
413  rowB = &Bt.m_rows[j][0];
414  for (k = 0; k < count; k ++) {
415  acc = acc + rowA[k] * rowB[k];
416 
417 #ifdef DG_COUNT_FLOAT_OPS
419 #endif
420  }
421  out[j] = acc;
422 
423 #ifdef DG_COUNT_FLOAT_OPS
425 #endif
426  }
427  }
428 }
429 
430 
431 
432 
433 template<class T>
435  dgInt32 i;
436  dgInt32 j;
437  dgInt32 k;
438  T *B;
439  T *rowI;
440  T *rowK;
441 
442  NEWTON_ASSERT(m_rowCount == m_colCount);
443  NEWTON_ASSERT(b.m_colCount == m_colCount);
444 
445  B = &b[0];
446  // convert to upper triangular matrix by applying gauss pivoting
447  for (i = 0; i < m_rowCount - 1; i ++) {
448  rowI = &m_rows[i][0];
449  T den(rowI[i]);
450 
451  if (T(dgAbsf(den)) < T(0.0f)) {
452  return false;
453  }
454 
455  for (k = i + 1; k < m_rowCount; k ++) {
456  rowK = &m_rows[k][0];
457  T num(rowK[i]);
458 
459  if (T(dgAbsf(num)) > tol) {
460  num = num / den;
461  for (j = i + 1; j < m_rowCount; j ++) {
462  rowK[j] = rowK[j] - rowI[j] * num;
463 
464 #ifdef DG_COUNT_FLOAT_OPS
467 #endif
468  }
469  B[k] = B[k] - B[i] * num;
470 
471 #ifdef DG_COUNT_FLOAT_OPS
474 #endif
475  }
476  }
477  }
478 
479 
480  B[m_rowCount - 1] = B[m_rowCount - 1] / m_rows[m_rowCount - 1][m_rowCount - 1];
481  for (i = m_rowCount - 2; i >= 0; i --) {
482  T acc(0);
483  rowI = &m_rows[i][0];
484  for (j = i + 1 ; j < m_rowCount; j ++) {
485  acc = acc + rowI[j] * B[j];
486 
487 #ifdef DG_COUNT_FLOAT_OPS
489 #endif
490  }
491  B[i] = (B[i] - acc) / rowI[i];
492 
493 #ifdef DG_COUNT_FLOAT_OPS
496 #endif
497  }
498 
499 #ifdef DG_COUNT_FLOAT_OPS
502 #endif
503 
504  return true;
505 }
506 
507 template<class T>
508 void dgGeneralMatrix<T>::SwapRows(dgInt32 i, dgInt32 j) {
509  NEWTON_ASSERT(i >= 0);
510  NEWTON_ASSERT(j >= 0);
511  NEWTON_ASSERT(i < m_rowCount);
512  NEWTON_ASSERT(j < m_rowCount);
513  NEWTON_ASSERT(j != i);
514  Swap(m_rows[i].m_columns, m_rows[j].m_columns);
515 }
516 
517 template<class T>
518 void dgGeneralMatrix<T>::SwapColumns(dgInt32 i, dgInt32 j) {
519  dgInt32 k;
520  NEWTON_ASSERT(i >= 0);
521  NEWTON_ASSERT(j >= 0);
522  NEWTON_ASSERT(i < m_colCount);
523  NEWTON_ASSERT(j < m_colCount);
524  for (k = 0; k < m_colCount; k ++) {
525  Swap(m_rows[k][i], m_rows[k][j]);
526  }
527 }
528 
529 
530 
531 template<class T>
532 bool dgGeneralMatrix<T>::TestSymetry() const {
533  dgInt32 i;
534  dgInt32 j;
535 
536  if (m_colCount != m_rowCount) {
537  return false;
538  }
539 
540  dgGeneralMatrix<T> mat = *this;
541  for (i = 0; i < m_rowCount; i ++) {
542  for (j = i + 1; j < m_rowCount; j ++) {
543  if (dgAbsf(mat[i][j] - mat[j][i]) > 1.0e-12f) {
544  return false;
545  }
546  }
547  }
548  return true;
549 }
550 
551 template<class T>
552 bool dgGeneralMatrix<T>::TestPSD() const {
553  if (!TestSymetry()) {
554  return false;
555  }
556 
557  dgGeneralMatrix<T> tmp(*this);
558  return tmp.CholeskyDecomposition();
559 }
560 
561 
562 
563 template<class T>
565  dgInt32 i;
566  dgInt32 j;
567  dgInt32 k;
568  T factor;
569  T *rowK;
570  T *rowJ;
571 
572 #ifdef DG_COUNT_FLOAT_OPS
573  dgInt32 memCount;
574  dgInt32 floatCount;
575 
577  floatCount = dgGeneralVector<T>::GetFloatOps();
578 #endif
579 
580  for (j = 0; j < m_rowCount; j++) {
581 //Trace ();
582 //dgTrace (("\n"));
583  rowJ = &m_rows[j].m_columns[0];
584 
585  for (k = 0; k < j; k ++) {
586  rowK = &m_rows[k].m_columns[0];
587 
588  factor = rowK[j];
589  if (dgAbsf(factor) > 1.0e-6f) {
590  for (i = j; i < m_rowCount; i ++) {
591  rowJ[i] -= rowK[i] * factor;
592 #ifdef DG_COUNT_FLOAT_OPS
593  memCount += 1;
594  floatCount += 2;
595 #endif
596  }
597  }
598  }
599 
600  factor = rowJ[j];
601  if (factor <= T(0.0f)) {
602  if (factor <= T(-5.0e-4f)) {
603  return false;
604  }
605  factor = T(1.0e-12f);
606  }
607 
608  factor = T(dgSqrt(dgFloat32(factor)));
609  rowJ[j] = factor;
610  factor = T(1.0f / dgFloat32(factor));
611 
612 #ifdef DG_COUNT_FLOAT_OPS
613  memCount += 1;
614  floatCount += 1;
615 #endif
616 
617  for (k = j + 1; k < m_rowCount; k ++) {
618  rowJ[k] *= factor;
619 #ifdef DG_COUNT_FLOAT_OPS
620  memCount += 1;
621  floatCount += 1;
622 #endif
623  }
624  }
625 
626 #ifdef DG_COUNT_FLOAT_OPS
629 #endif
630 
631  return true;
632 }
633 
634 
635 #endif
636 
Definition: dgGeneralVector.h:34
Definition: dgGeneralMatrix.h:40