KSquare Utilities
Matrix.cpp
Go to the documentation of this file.
1 /* Matrix.cpp -- A simple two dimensional floating point matrix.
2  * Copyright (C) 1994-2014 Kurt Kramer
3  * For conditions of distribution and use, see copyright notice in KKB.h
4  */
5 #include "FirstIncludes.h"
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <math.h>
10 #include <fstream>
11 #include <iostream>
12 #include <ostream>
13 #include <vector>
14 #include "MemoryDebug.h"
15 using namespace std;
16 
17 
18 #include "Matrix.h"
19 
20 #include "KKException.h"
21 #include "OSservices.h"
22 #include "KKStr.h"
23 using namespace KKB;
24 
25 
26 Row::Row ():
27  cells (NULL),
28  numOfCols (-1)
29 {
30 }
31 
32 
33 
34 Row::Row (kkint32 _numOfCols,
35  double* _cells
36  ):
37  cells (_cells),
38  numOfCols (_numOfCols)
39 {
40  if (_numOfCols < 0)
41  {
42  KKStr msg;
43  msg << "Row::Row **** ERROR **** Invalid Dimension[" << _numOfCols << "].";
44  cerr << std::endl << msg << std::endl << std::endl;
45  throw KKException (msg);
46  }
47 }
48 
49 
50 
51 Row::Row (const Row& _row):
52  cells (_row.cells),
53  numOfCols (_row.numOfCols)
54 {
55 }
56 
57 
58 
59 Row::~Row ()
60 {
61  cells = NULL;
62 }
63 
64 
65 
66 void Row::Define (kkint32 _numOfCols,
67  double* _cells
68  )
69 {
70  numOfCols = _numOfCols;
71  cells = _cells;
72 }
73 
74 
75 
76 double& Row::operator[] (kkint32 idx)
77 {
78  if ((idx < 0) || (idx >= numOfCols))
79  {
80  cerr << std::endl
81  << "Row::operator[] **** ERROR ****, Index["
82  << idx << "] out of range of [0-" << numOfCols << "]."
83  << std::endl;
85  exit (1);
86  }
87 
88  return cells[idx];
89 } /* Row::operator[] */
90 
91 
92 
93 
95 
96  data (NULL),
97  dataArea (NULL),
98  numOfCols (0),
99  numOfRows (0),
100  rows (NULL),
101  totNumCells (0)
102 {
103 }
104 
105 
106 
107 
108 Matrix::Matrix (kkint32 _numOfRows,
109  kkint32 _numOfCols
110  ):
111 
112  data (NULL),
113  dataArea (NULL),
114  numOfCols (_numOfCols),
115  numOfRows (_numOfRows),
116  rows (NULL),
117  totNumCells (0)
118 
119 {
120  if (_numOfRows < 0)
121  {
122  KKStr msg(80);
123  msg << "Matrix::Matrix **** ERROR ****, Row Dimension[" << _numOfRows << "] Invalid.";
124  cerr << std::endl << msg <<std::endl << std::endl;
125  throw KKException (msg);
126  }
127 
128  if (_numOfCols < 0)
129  {
130  KKStr msg(80);
131  msg << "Matrix::Matrix **** ERROR ****, Col Dimension[" << _numOfCols << "] Invalid.";
132  cerr << std::endl << msg <<std::endl << std::endl;
133  throw KKException (msg);
134  }
135 
136  AllocateStorage ();
137 } /* Matrix::Matrix */
138 
139 
140 
141 
142 Matrix::Matrix (const Matrix& _matrix):
143  data (NULL),
144  dataArea (NULL),
145  numOfCols (_matrix.numOfCols),
146  numOfRows (_matrix.numOfRows),
147  rows (NULL),
148  totNumCells (0)
149 
150 {
151  AllocateStorage ();
152  memcpy (dataArea, _matrix.dataArea, totNumCells * sizeof (double));
153 } /* Matrix::Matrix */
154 
155 
156 
158  data (NULL),
159  dataArea (NULL),
160  numOfCols (1),
161  numOfRows (kkint32 (_v.size ())),
162  rows (NULL)
163 {
164  AllocateStorage ();
165  kkint32 row;
166  for (row = 0; row < numOfRows; ++row)
167  dataArea[row] = _v[row];
168 } /* Matrix::Matrix */
169 
170 
171 
172 
174 {
175  Destroy ();
176 }
177 
178 
179 
180 /**
181  *@brief Will create a new matrix using the 2dArray "data" for source.
182  *@details If any row in "data" is equal to NULL then the corresponding row
183  * in the returned matrix will be initialized to zeros.
184  *@param[in] numOfRows Number of rows in resultant matrix.
185  *@param[in] numOfCols Number of cols if resultant matrix.
186  *@param[in] data A two dimensional array.
187  *@return A matrix that is initialized with the contents of "data".
188  */
189 template<typename T>
190 MatrixPtr Matrix::BuildFromArray (kkint32 numOfRows,
191  kkint32 numOfCols,
192  T** data
193  )
194 {
195  if ((numOfRows < 1) || (numOfCols < 1))
196  {
197  cerr << std::endl << std::endl << "Matrix::BuildFromArray ***ERROR*** NumOfRows[" << numOfRows << "] or NumOfCols[" << numOfCols << "] is invalid." << std::endl << std::endl;
198  return NULL;
199  }
200 
201  if (!data)
202  {
203  cerr << std::endl << std::endl << "Matrix::BuildFromArray ***ERROR*** No source data (data == NULL)." << std::endl << std::endl;
204  return NULL;
205  }
206 
207  MatrixPtr m = new Matrix (numOfRows, numOfCols);
208 
209  for (kkint32 row = 0; row < numOfRows; ++row)
210  {
211  T* srcRow = data[row];
212  double* destRow = m->data[row];
213  if (srcRow)
214  {
215  for (kkint32 col = 0; col < numOfCols; ++col)
216  destRow[col] = (double)(srcRow[col]);
217  }
218  }
219  return m;
220 } /* BuildFromArray */
221 
222 
223 
224 void Matrix::ReSize (kkint32 _numOfRows,
225  kkint32 _numOfCols
226  )
227 {
228  Destroy ();
229  numOfRows = _numOfRows;
230  numOfCols = _numOfCols;
231  AllocateStorage ();
232 } /* ReSize */
233 
234 
235 
236 
237 void Matrix::AllocateStorage ()
238 {
239  totNumCells = numOfRows * numOfCols;
240  dataArea = new double[totNumCells];
241  data = new double*[numOfRows];
242  rows = new Row [numOfRows];
243 
244  kkint32 x;
245 
246  for (x = 0; x < totNumCells; ++x)
247  dataArea[x] = 0.0;
248 
249 
250  double* dataAreaPtr = dataArea;
251  for (x = 0; x < numOfRows; x++)
252  {
253  rows[x].Define (numOfCols, dataAreaPtr);
254  data[x] = dataAreaPtr;
255  dataAreaPtr += numOfCols;
256  }
257 } /* AllocateStorage */
258 
259 
260 
261 void Matrix::Destroy ()
262 {
263  delete[] rows; rows = NULL;
264  delete[] data; data = NULL;
265  delete[] dataArea; dataArea = NULL;
266 }
267 
268 
269 
270 Row& Matrix::operator[] (kkint32 rowIDX) const
271 {
272  if ((rowIDX < 0) || (rowIDX >= numOfRows))
273  {
274  KKStr msg (80);
275  msg << "Matrix::operator[] **** ERROR ****, Row Index[" << rowIDX << "] Invalid.";
276  cerr << std::endl << msg << std::endl << std::endl;
277  throw KKException (msg);
278  }
279 
280  return (rows[rowIDX]);
281 } /* Matrix::operator[] */
282 
283 
284 
285 
287 {
288  if (numOfCols != numOfRows)
289  {
290  KKStr msg (80);
291  msg << "Matrix::Determinant *** ERROR *** Dimensions are not Square[" << numOfRows << "," << numOfCols << "] Invalid.";
292  cerr << std::endl << msg << std::endl << std::endl;
293  throw KKException (msg);
294  }
295 
296  if (numOfCols == 1)
297  {
298  // return rows[0]->cells[0];
299  return data[0][0];
300  }
301 
302  kkint32 x;
303 
304  kkint32* rowMap = new kkint32[numOfRows];
305  for (x = 0; x < numOfRows; x++)
306  rowMap[x] = x;
307 
308  kkint32* colMap = new kkint32[numOfCols];
309  for (x = 0; x < numOfCols; x++)
310  colMap[x] = x;
311 
312  double det = CalcDeterminent (rowMap, colMap, numOfCols);
313 
314  delete[] colMap;
315  return det;
316 } /* Determinant */
317 
318 
319 /*
320 Matrix& Matrix::Invert ()
321 {
322 
323 
324 }
325 
326 */
327 
328 
329 Matrix& Matrix::operator= (const Matrix& right)
330 {
331  ReSize (right.numOfRows, right.numOfCols);
332  memcpy (dataArea, right.dataArea, totNumCells * sizeof (double));
333  return *this;
334 }
335 
336 
338 {
339  ReSize ((kkuint32)right.size (), 1);
340  for (kkint32 row = 0; row < numOfRows; row++)
341  dataArea[row] = right[row];
342 
343  return *this;
344 } /* operator= */
345 
346 
347 
348 
349 Matrix& Matrix::operator*= (double right)
350 {
351  kkint32 x = 0;
352  for (x = 0; x < totNumCells; ++x)
353  dataArea[x] *= right;
354  return *this;
355 }
356 
357 
358 
359 Matrix& Matrix::operator+= (double right)
360 {
361  kkint32 x = 0;
362  for (x = 0; x < totNumCells; ++x)
363  dataArea[x] += right;
364  return *this;
365 }
366 
367 
368 
369 Matrix Matrix::operator+ (const Matrix& right)
370 {
371  if ((numOfRows != right.numOfRows) ||
372  (numOfCols != right.numOfCols))
373  {
374  KKStr msg (100);
375  msg << "Matrix::operator+ **** ERROR ****, Dimensions Don't Match [" << numOfRows << "," << numOfCols << "] + [" << right.numOfRows << "," << right.numOfCols << "].";
376  cerr << std::endl << msg << std::endl << std::endl;
377  throw KKException (msg);
378  }
379 
380  Matrix result (*this);
381 
382  double* resultDataArea = result.dataArea;
383  double* rightDataArea = right.dataArea;
384 
385  for (kkint32 x = 0; x < totNumCells; ++x)
386  resultDataArea[x] = dataArea[x] + rightDataArea[x];
387 
388  return result;
389 } /* Matrix::operator+ */
390 
391 
392 
393 
394 
395 
396 Matrix& Matrix::operator+= (const Matrix& right)
397 {
398  if ((numOfRows != right.numOfRows) ||
399  (numOfCols != right.numOfCols))
400  {
401  KKStr msg (100);
402  msg << "Matrix::operator+= **** ERROR ****, Dimensions Don't Match [" << numOfRows << "," << numOfCols << "] + [" << right.numOfRows << "," << right.numOfCols << "].";
403  cerr << std::endl << msg << std::endl << std::endl;
404  throw KKException (msg);
405  }
406 
407  double* rightDataArea = right.dataArea;
408 
409  for (kkint32 x = 0; x < totNumCells; ++x)
410  dataArea[x] += rightDataArea[x];
411 
412  return *this;
413 } /* Matrix::operator+ */
414 
415 
416 
417 
418 
419 Matrix Matrix::operator- (const Matrix& right)
420 {
421  if ((numOfRows != right.numOfRows) ||
422  (numOfCols != right.numOfCols))
423  {
424  KKStr msg (100);
425  msg << "Matrix::operator- **** ERROR ****, Dimensions Don't Match [" << numOfRows << "," << numOfCols << "] + [" << right.numOfRows << "," << right.numOfCols << "].";
426  cerr << std::endl << msg << std::endl << std::endl;
427  throw KKException (msg);
428  }
429 
430  Matrix result (*this);
431 
432  double* resultDataArea = result.dataArea;
433  double* rightDataArea = right.dataArea;
434 
435  for (kkint32 x = 0; x < totNumCells; ++x)
436  resultDataArea[x] = dataArea[x] - rightDataArea[x];
437 
438  return result;
439 } /* operator- */
440 
441 
442 
443 Matrix Matrix::operator- (double right)
444 {
445  Matrix result (*this);
446  double* resultDataArea = result.dataArea;
447  for (kkint32 x = 0; x < totNumCells; ++x)
448  resultDataArea[x] = dataArea[x] - right;
449 
450  return result;
451 }
452 
453 
454 
455 
456 Matrix KKB::operator- (double left,
457  const Matrix& right
458  )
459 {
460  kkint32 numOfRows = right.NumOfRows ();
461  kkint32 numOfCols = right.NumOfCols ();
462  kkint32 totNumCells = right.totNumCells;
463 
464  Matrix result (numOfRows, numOfCols);
465  double* resultDataArea = result.dataArea;
466  double* rightDataArea = right.dataArea;
467 
468  for (kkint32 x = 0; x < totNumCells; ++x)
469  resultDataArea[x] = left - rightDataArea[x];
470 
471  return result;
472 } /* operator- */
473 
474 
475 
476 
477 
478 Matrix Matrix::operator* (const Matrix& right)
479 {
480  if (numOfCols != right.numOfRows)
481  {
482  KKStr msg (100);
483  msg << "Matrix::operator* **** ERROR ****, Dimension Mismatch Left[" << numOfRows << "," << numOfCols << "] Right[" << right.numOfRows << "," << right.numOfCols << "].";
484  cerr << std::endl << msg << std::endl << std::endl;
485  throw KKException (msg);
486  }
487 
488  kkint32 col;
489  kkint32 row;
490 
491  kkint32 rRows = numOfRows;
492  kkint32 rCols = right.numOfCols;
493 
494  Matrix result (rRows, rCols);
495 
496  double** resultData = result.data;
497  double** rightData = right.data;
498 
499  kkint32 innerDim = numOfCols;
500 
501  for (row = 0; row < rRows; row++)
502  {
503  for (col = 0; col < rCols; col++)
504  {
505  double val = 0;
506  kkint32 x = 0;
507  for (x = 0; x < innerDim; x++)
508  val = val + data[row][x] * rightData[x][col];
509  resultData[row][col] = val;
510  }
511  }
512 
513  return result;
514 } /* Matrix::operator */
515 
516 
517 
518 
519 Matrix Matrix::operator+ (double right)
520 {
521  Matrix result (*this);
522  double* resultDataArea = result.dataArea;
523  for (kkint32 x = 0; x < totNumCells; ++x)
524  resultDataArea[x] = dataArea[x] + right;
525  return result;
526 } /* operator+ */
527 
528 
529 
530 Matrix Matrix::operator* (double right)
531 {
532  Matrix result (*this);
533  double* resultDataArea = result.dataArea;
534  for (kkint32 x = 0; x < totNumCells; ++x)
535  resultDataArea[x] = dataArea[x] * right;
536  return result;
537 } /* operator* */
538 
539 
540 
541 /**
542  *@brief Computes the Determinant using a recursive algorithm and co-factors matrixes.
543  *@details Very inefficient implementation, would only use on very small matrices. *
544  */
545 double Matrix::CalcDeterminent (kkint32* rowMap,
546  kkint32* colMap,
547  kkint32 size
548  )
549 
550 {
551  if (size == 2)
552  {
553  double* topCols = data[rowMap[0]];
554  double* botCols = data[rowMap[1]];
555  return topCols[colMap[0]] * botCols[colMap[1]] - topCols[colMap[1]] * botCols[colMap[0]];
556  }
557 
558  double* coFactors = data[rowMap[0]];
559  double det = 0.0;
560  kkint32 newSize = size - 1;
561  kkint32 row;
562  kkint32 sign = 1;
563 
564 
565  kkint32* newRowMap = new kkint32[newSize];
566 
567  for (row = 1; row < size; row++)
568  {
569  newRowMap[row - 1] = rowMap[row];
570  }
571 
572  kkint32 cfCol;
573  for (cfCol = 0; cfCol < size; cfCol++)
574  {
575  kkint32* newColMap = new kkint32[newSize];
576 
577  kkint32 oldCol;
578  kkint32 newCol = 0;
579  for (oldCol = 0; oldCol < size; oldCol++)
580  {
581  if (oldCol != cfCol)
582  {
583  newColMap[newCol] = colMap[oldCol];
584  newCol++;
585  }
586  }
587 
588  det = det + sign * coFactors[colMap [cfCol]] * CalcDeterminent (newRowMap, newColMap, newSize);
589  if (sign > 0)
590  sign = -1;
591  else
592  sign = 1;
593 
594  delete[] newColMap;
595  }
596 
597  delete[] newRowMap;
598 
599  return det;
600 } /* CalcDeterminent */
601 
602 
603 
604 
605 
607 {
608  if (numOfCols != numOfRows)
609  {
610  cerr << std::endl
611  << "Matrix::CalcCoFactors **** ERROR ****, Matrix not a Square["
612  << numOfRows << "," << numOfCols << "]."
613  << std::endl
614  << std::endl;
616  exit (1);
617  }
618 
619  MatrixPtr result = new Matrix (numOfRows, numOfCols);
620 
621  kkint32 newSize = numOfCols - 1;
622 
623  kkint32* colMap = new kkint32 [newSize];
624  kkint32* rowMap = new kkint32 [newSize];
625 
626  kkint32 row;
627  kkint32 col;
628  kkint32 x;
629 
630 
631  kkint32 sign;
632 
633  for (row = 0; row < numOfRows; row++)
634  {
635  // Create a map of all rows except row we are calculating
636  // CoFactors for.
637 
638  kkint32 newRow = 0;
639  for (x = 0; x < numOfRows; x++)
640  {
641  if (x != row)
642  {
643  rowMap[newRow] = x;
644  newRow++;
645  }
646  }
647 
648  for (col = 0; col < numOfCols; col++)
649  {
650  // Create a map of all cells except row we are calculating
651  // CoFactor for.
652 
653  kkint32 newCol = 0;
654  for (x = 0; x < numOfCols; x++)
655  {
656  if (x != col)
657  {
658  colMap[newCol] = x;
659  newCol++;
660  }
661  }
662 
663  if (((row + col) % 2) == 0)
664  sign = 1;
665  else
666  sign = -1;
667 
668 
669  Matrix temp (newSize, newSize);
670  for (kkint32 r = 0; r < newSize; r++)
671  {
672  kkint32 tempR = rowMap[r];
673  for (kkint32 c = 0; c < newSize; c++)
674  temp[r][c] = data[tempR][colMap[c]];
675  }
676 
677  result->data[row][col] = temp.Determinant () * sign;
678  }
679  }
680 
681  return result;
682 } /* CalcCoFactor */
683 
684 
685 
686 
687 
688 bool Matrix::Symmetric () const
689 {
690  if ((data == NULL) || (numOfRows != numOfCols))
691  return false;
692 
693  for (kkint32 row = 0; row < numOfRows; ++row)
694  {
695  for (kkint32 col = row + 1; col < numOfCols; ++col)
696  {
697  if (data[row][col] != data[col][row])
698  return false;
699  }
700  }
701  return true;
702 } /* Symmetric */
703 
704 
705 
706 
708 {
709  kkint32 col;
710  kkint32 row;
711 
712  Matrix result (numOfCols, numOfRows);
713 
714  double** resultData = result.data;
715 
716  for (row = 0; row < numOfRows; row++)
717  {
718  for (col = 0; col < numOfCols; col++)
719  {
720  resultData[col][row] = data[row][col];
721  }
722  }
723 
724  return result;
725 } /* Transpose */
726 
727 
728 
729 
730 
732 {
733  if (numOfCols != numOfRows)
734  {
735  KKStr msg (80);
736  msg << "Matrix::Inverse *** ERROR *** Dimensions are not Square[" << numOfRows << "," << numOfCols << "] Invalid.";
737 
738  cerr << std::endl << msg << std::endl << std::endl;
739  throw KKException (msg);
740  }
741 
742  double det = Determinant ();
743  if (det == 0)
744  {
745  cerr << std::endl << "Matrix::Inverse *** ERROR *** Determinant of Matrix is Zero." << std::endl << std::endl;
746  }
747 
748  MatrixPtr coFactors = CalcCoFactorMatrix ();
749 
750  Matrix result = coFactors->Transpose ();
751 
752  delete coFactors;
753 
754  if (det == 0.0)
755  result *= 0.0;
756  else
757  result *= (1.0 / det);
758 
759  return result;
760 } /* Inverse */
761 
762 
763 
764 /**
765  *@brief Will derive the Eigen vectors and values of the matrix.
766  *@details Will make use of routines from Numerical Recipes for c++, ex: Tred2 and Tqli.
767  */
768 void Matrix::EigenVectors (MatrixPtr& eigenVectors,
769  VectorDouble*& eigenValues
770  ) const
771 {
772  eigenVectors = NULL;
773  eigenValues = NULL;
774  if ((data == NULL) || (numOfRows < 1))
775  {
776  cerr << std::endl << "Matrix::EigenVectors ***ERROR*** 'data' not defined in Matrix." << std::endl << std::endl;
777  return;
778  }
779 
780  if (numOfRows != numOfCols)
781  {
782  cerr << std::endl << "Matrix::EigenVectors ***ERROR*** Not a square matrix NumOfRows[" << numOfRows << "] NumOfCols[" << numOfCols << "]." << std::endl << std::endl;
783  return;
784  }
785 
786  eigenVectors = new Matrix (*this);
787 
788  if (Symmetric ())
789  {
790  double* d = new double[numOfRows];
791  double* e = new double[numOfRows];
792  for (kkint32 x = 0; x < numOfRows; ++x)
793  {
794  d[x] = 0.0;
795  e[x] = 0.0;
796  }
797  Tred2 (eigenVectors->data, numOfRows, d, e);
798  kkint32 successful = Tqli (d, e, numOfRows, eigenVectors->data);
799  if (successful != 1)
800  {
801  delete eigenVectors; eigenVectors = NULL;
802  delete[] d; d = NULL;
803  delete[] e; e = NULL;
804  return;
805  }
806 
807  eigenValues = new VectorDouble ();
808  for (kkint32 x = 0; x < numOfRows; ++x)
809  eigenValues->push_back (d[x]);
810 
811  delete[] d; d = NULL;
812  delete[] e; e = NULL;
813  }
814 } /* GetEigenVectors */
815 
816 
817 
818 void Matrix::FindMaxValue (double& maxVal,
819  kkint32& rowIdx,
820  kkint32& colIdx
821  )
822 {
823  rowIdx = -1;
824  colIdx = -1;
825  maxVal = DBL_MIN;
826 
827  if (!data)
828  return;
829 
830  maxVal = data[0][0];
831  rowIdx = colIdx = 0;
832 
833  for (kkint32 row = 0; row < numOfRows; ++row)
834  {
835  double* dataRow = data[row];
836  for (kkint32 col = 0; col < numOfCols; ++col)
837  {
838  if (dataRow[col] > maxVal)
839  {
840  maxVal = dataRow[col];
841  colIdx = col;
842  rowIdx = row;
843  }
844  }
845  }
846 
847  return;
848 } /* FindMaxValue */
849 
850 
851 
852 
853 ostream& operator<< ( ostream& os,
854  const Matrix& matrix
855  )
856 {
857  kkint32 col;
858  kkint32 row;
859 
860  os << "[" << matrix.NumOfRows () << "," << matrix.NumOfCols () << "]" << std::endl;
861 
862  os << "[";
863 
864  for (row = 0; row < matrix.NumOfRows (); row++)
865  {
866  if (row > 0)
867  os << " ";
868 
869  os << "[";
870 
871  for (col = 0; col < matrix.NumOfCols (); col++)
872  {
873  if (col > 0)
874  os << ", ";
875 
876  os.width (8);
877  os.precision (6);
878  os << matrix[row][col];
879  }
880 
881  os << "]" << std::endl;
882  }
883 
884  os << "]" << std::endl;
885 
886  return os;
887 } /* operator<< */
888 
889 
890 
892 {
893  VectorDouble colResult (numOfRows, 0.0);
894  for (kkint32 r = 0; r < numOfRows; r++)
895  colResult[r] = data[r][col];
896 
897  return colResult;
898 } /* GetCol */
899 
900 
901 #if !defined(DBL_EPSILON)
902 #define DBL_EPSILON 2.2204460492503131e-016
903 #endif
904 
905 /**
906  * @param mat
907  * @param offset
908  * @return A[offset][offset]
909  */
910 double Matrix::DeterminantSwap (double** mat,
911  unsigned short offset
912  )
913 
914 {
915  if (fabs(mat[offset][offset]) < DBL_EPSILON)
916  {
917  for (ushort i = offset + 1; i < numOfRows; i++)
918  {
919  if (fabs (mat[i][offset]) >= DBL_EPSILON)
920  {
921  /*
922  * Swap line `i' and line `offset'
923  */
924  double *tmp;
925 
926  tmp=mat[offset];
927  mat[offset]=mat[i];
928  mat[i]=tmp;
929  break;
930  }
931  }
932  }
933 
934  return (mat[offset][offset]);
935 } /* DeterminantSwap */
936 
937 
938 
939 
940 
941 
942 /**
943  * @return the determinant of mat
944  */
945 double Matrix::Determinant ()
946 {
947  if (numOfCols != numOfRows)
948  return -999999.99;
949 
950  kkint32 r, c;
951 
952  double** mat = new double*[numOfRows];
953  for (r = 0; r < numOfRows; r++)
954  {
955  mat[r] = new double[numOfCols];
956  for (c = 0; c < numOfCols; c++)
957  {
958  mat[r][c] = data[r][c];
959  }
960  }
961 
962  double det = 1.0;
963  unsigned short i = 0;
964 
965  for (i = 0; i < numOfRows; i++)
966  {
967  const double Aii = DeterminantSwap (mat, i);
968  unsigned short j = 0;
969 
970  if (fabs (Aii) < DBL_EPSILON)
971  {
972  det = 0.0;
973  break;
974  }
975 
976  det *= Aii;
977 
978  //Do elimination
979  for (j = i + 1; j < numOfRows; j++)
980  {
981  const double pivot = mat[j][i] / Aii;
982  for (ushort k = i; k < numOfRows; k++)
983  mat[j][k] -= pivot * mat[i][k];
984  }
985  }
986 
987  for (r = 0; r < numOfRows; r++)
988  {
989  delete mat[r];
990  mat[r] = NULL;
991  }
992  delete[] mat;
993  mat = NULL;
994  return (det);
995 } /* Determinant */
996 
997 
998 /**
999  *@brief Returns a Covariance matrix.
1000  *@details Each column represents a variable and each row represents an instance of each variable.
1001  *@return Returns a symmetric matrix that will be (numOfRows x numOfRows) where each element will represent the covariance
1002  * between their respective variables.
1003  */
1004 MatrixPtr Matrix::Covariance () const
1005 {
1006  if ((data == NULL) || (numOfRows < 1))
1007  {
1008  cerr << std::endl << "Matrix::Covariance ***ERROR*** 'data' not defined in Matrix." << std::endl << std::endl;
1009  return NULL;
1010  }
1011 
1012  // Used web site below to help with Covariance calculations
1013  // http://www.itl.nist.gov/div898/handbook/pmc/section5/pmc541.htm
1014 
1015  kkint32 col = 0;
1016  kkint32 row = 0;
1017 
1018  double* totals = new double[numOfCols];
1019  double* means = new double[numOfCols];
1020  double** centeredVals = new double*[numOfCols];
1021  for (col = 0; col < numOfCols; ++col)
1022  {
1023  totals[col] = 0.0;
1024  centeredVals[col] = new double[numOfRows];
1025  }
1026 
1027  for (row = 0; row < numOfRows; ++row)
1028  {
1029  double* rowData = data[row];
1030  for (col = 0; col < numOfCols; ++col)
1031  totals[col] += rowData[col];
1032  }
1033 
1034  for (col = 0; col < numOfCols; ++col)
1035  means[col] = totals[col] / numOfRows;
1036 
1037  for (row = 0; row < numOfRows; ++row)
1038  {
1039  double* rowData = data[row];
1040  for (col = 0; col < numOfCols; ++col)
1041  centeredVals[col][row] = rowData[col] - means[col];
1042  }
1043 
1044  MatrixPtr covariances = new Matrix (numOfCols, numOfCols);
1045 
1046  for (kkint32 varIdxX = 0; varIdxX < numOfCols; ++varIdxX)
1047  {
1048  double* varXs = centeredVals[varIdxX];
1049  for (kkint32 varIdxY = varIdxX; varIdxY < numOfCols; ++varIdxY)
1050  {
1051  // Calculate the covariance between chanIdx0 and chanIdx1
1052 
1053  double* varYs = centeredVals[varIdxY];
1054  double total = 0.0f;
1055  for (row = 0; row < numOfRows; ++row)
1056  total += varXs[row] * varYs[row];
1057  (*covariances)[varIdxX][varIdxY] = total / (numOfRows - 1);
1058  (*covariances)[varIdxY][varIdxX] = (*covariances)[varIdxX][varIdxY];
1059  }
1060  }
1061 
1062  for (col = 0; col < numOfCols; col++)
1063  {
1064  delete[] centeredVals[col];
1065  centeredVals[col] = NULL;
1066  }
1067  delete[] centeredVals; centeredVals = NULL;
1068  delete[] means; means = NULL;
1069  delete[] totals; totals = NULL;
1070 
1071  return covariances;
1072 } /* Covariance */
1073 
1074 
1075 
1076 
1077 /**
1078  *@brief Householder reduction of a real symmetric matrix a[0..n-1][0..n-1].
1079  *@details From Numerical Recipes in c++, page 479. Tred2 is designed to work with Tqli. Its purpose
1080  * is to reduce the matrix 'a' from a symmetric matrix to a orthogonal matrix.
1081  *@param[in,out] a On output a is replaced by the orthogonal matrix Q effecting the transform.
1082  *@param[in] n Size of matrix is (n x n).
1083  *@param[out] d Returns the diagonal elements of the tridiagonal matrix,
1084  *@param[out] e The off-diagonal elements with e[0] = 0.
1085  */
1086 void Matrix::Tred2 (double** a,
1087  kkint32 n,
1088  double* d,
1089  double* e
1090  ) const
1091 {
1092  kkint32 i, j, k, l;
1093 
1094  double scale, hh, h, g, f;
1095 
1096  for (i = n - 1; i > 0; i--)
1097  {
1098  l = i - 1;
1099  h = scale = 0.0;
1100 
1101  if (l > 0)
1102  {
1103  for (k = 0; k < l + 1; k++)
1104  scale += fabs (a[i][k]);
1105 
1106  if (scale == 0.0)
1107  {
1108  e[i] = a[i][l];
1109  }
1110 
1111  else
1112  {
1113  for (k = 0; k < l + 1; k++)
1114  {
1115  a[i][k] /= scale; // Use scaled a's for transformation
1116  h+= a[i][k] * a[i][k]; // h = sigma
1117  }
1118 
1119  f = a[i][l];
1120  g = (f > 0 ? -sqrt(h) : sqrt(h));
1121  e[i] = scale * g;
1122  h -= f * g;
1123  a[i][l] = f - g;
1124  f = 0.0;
1125 
1126  for (j = 0; j < l + 1; j++)
1127  {
1128  a[j][i] = a[i][j] / h;
1129  g = 0.0;
1130  for (k = 0; k < j + 1; k++)
1131  g += a[j][k] * a[i][k];
1132 
1133  for (k = j + 1; k < l + 1; k++)
1134  g += a[k][j] * a[i][k];
1135 
1136  e[j] = g / h;
1137 
1138  f += e[j] * a[i][j];
1139  } /* for (j = 0; */
1140 
1141  hh = f / (h + h);
1142 
1143  for (j = 0; j < l + 1; j++)
1144  {
1145  f = a[i][j];
1146  e[j] = g = e[j] - hh * f;
1147  for (k = 0; k < j + 1; k++)
1148  a[j][k] -= (f * e[k] + g * a[i][k]);
1149  }
1150  }
1151  } /* if (l > 0) */
1152  else
1153  {
1154  e[i] = a[i][l];
1155  }
1156 
1157  d[i] = h;
1158  }
1159 
1160  // We can now calculate Eigen Vectors
1161 
1162  d[0] = 0.0;
1163  e[0] = 0.0;
1164 
1165  for (i = 0; i < n; i++)
1166  {
1167  l = i;
1168 
1169  if (d[i] != 0.0)
1170  {
1171  for (j = 0; j < l; j++)
1172  {
1173  g = 0.0;
1174  for (k = 0; k < l; k++)
1175  g += a[i][k] * a[k][j];
1176 
1177  for (k = 0; k < l; k++)
1178  a[k][j] -= g * a[k][i];
1179  }
1180  }
1181 
1182  d[i] = a[i][i];
1183 
1184  // Reset row and column of 'a' to identity matrix;
1185  a[i][i] = 1.0;
1186  for (j = 0; j < l; j++)
1187  a[j][i] = a[i][j] = 0.0;
1188  } /* for (i) */
1189 
1190 } /* Tred2 */
1191 
1192 
1193 
1194 
1195 template<class T>
1196 inline const T SIGN (const T& a,
1197  const T& b
1198  )
1199 {
1200  if (b >= 0)
1201  {
1202  if (a >= 0)
1203  return a;
1204  else
1205  return -a;
1206  }
1207 
1208  else
1209  {
1210  if (a >- 0)
1211  return -a;
1212  else
1213  return a;
1214  }
1215 } /* SIGN */
1216 
1217 
1218 #define SQR(X) ((X) * (X))
1219 
1220 // Computes sqrt (a^2 + b^2) without destructive underflow or overflow
1221 double Matrix::Pythag (const double a,
1222  const double b
1223  ) const
1224 {
1225  double absa, absb;
1226 
1227  absa = fabs (a);
1228  absb = fabs (b);
1229 
1230  if (absa > absb)
1231  {
1232  return absa * sqrt (1.0 + SQR (absb / absa));
1233  }
1234  else
1235  {
1236  if (absb == 0.0)
1237  return 0.0;
1238  else
1239  return absb * sqrt (1.0 + SQR (absa / absb));
1240  }
1241 } /* pythag */
1242 
1243 
1244 
1245 //#undef SIGN
1246 
1247 //#define SIGN(a,b) ((b)<0 ? -fabs(a) : fabs(a))
1248 
1249 
1250 
1251 /**
1252  *@brief Determines the eigenvalues and eigen-vectors of a real symmetric, tridiagonal matrix previously reduced by Tred2.
1253  *@details TQLI = "Tridiagonal QL Implicit".
1254  *@param[in,out] d contains the diagonal elements of the tridiagonal matrix. On output will contain the eigenvalues.
1255  *@param[in] e On input contains the sub-diagonal of the tridiagonal matrix, with e[0] arbitrary. On output e is destroyed.
1256  *@param[in] n Size of matrix side.
1257  *@param[in,out] z If eigen-vectors of Tridiagonal matrix are required input as a identity matrix[0..n-1][o..n-1]. If
1258  * Eigen-vectors of input matrix to "Tred2" are required then z should equal the output matrix from
1259  * Tred2 "a".
1260  */
1261 kkint32 Matrix::Tqli (double* d,
1262  double* e,
1263  kkint32 n,
1264  double** z
1265  ) const
1266 {
1267  kkint32 m, l, iter, i, k;
1268  double s, r, p,g, f, dd, c, b;
1269 
1270  for (i = 1; i < n; i++)
1271  e[i - 1] = e[i];
1272 
1273  e[n - 1] = 0.0;
1274 
1275  for (l = 0; l < n; l++)
1276  {
1277  iter = 0;
1278 
1279  do
1280  {
1281  for (m = l; m < n - 1; m++)
1282  {
1283  // Looking for a single small sub-diagonal element
1284  // to split the matrix
1285  dd = fabs (d[m]) + fabs (d[m + 1]);
1286  if (fabs (e[m]) + dd == dd)
1287  break;
1288  }
1289 
1290  if (m != l)
1291  {
1292  if (iter == 100)
1293  {
1294  cerr << std::endl << std::endl
1295  << "Matrix::tqli **** ERROR **** To many iterations in tqli" << std::endl
1296  << std::endl;
1297  //osWaitForEnter ();
1298  //exit (-1);
1299  return 0;
1300  }
1301  iter++;
1302 
1303  g = (d[l + 1] - d[l]) / (2.0 * e[l]);
1304  r = Pythag (g, 1.0);
1305  g = d[m] - d[l] + e[l] / (g + SIGN (r, g));
1306  s = c = 1.0;
1307  p = 0.0;
1308 
1309  for (i = m - 1; i >= l; i--)
1310  {
1311  f = s * e[i];
1312  b = c * e[i];
1313  e[i + 1] = (r = Pythag (f, g));
1314  if (r == 0.0)
1315  {
1316  d[i + 1] -= p;
1317  e[m] = 0.0;
1318  break;
1319  }
1320 
1321  s = f / r;
1322  c = g / r;
1323  g = d[i + 1] - p;
1324  r = (d[i] - g) * s + 2.0 * c * b;
1325  d[i + 1] = g + (p = s * r);
1326  g = c * r - b;
1327 
1328  // Next loop can be omitted if eigen-vectors not wanted
1329 
1330  for (k = 0; k < n; k++)
1331  {
1332  f = z[k][i + 1];
1333  z[k][i + 1] = s * z[k][i] + c * f;
1334  z[k][i] = c * z[k][i] - s * f;
1335  } /* for (k) */
1336 
1337  } /* for (i) */
1338 
1339  if ((r == 0.0) && (i >= l))
1340  continue;
1341 
1342  d[l] -= p;
1343  e[l] = g;
1344  e[m] = 0.0;
1345  }
1346  }
1347  while (m != l);
1348 
1349  } /* for (l) */
1350 
1351  return (1);
1352 } /* Tqli*/
Row & operator[](kkint32 rowIDX) const
Definition: Matrix.cpp:270
KKStr(kkint32 size)
Creates a KKStr object that pre-allocates space for &#39;size&#39; characters.
Definition: KKStr.cpp:655
Matrix Transpose()
Definition: Matrix.cpp:707
#define DBL_EPSILON
Definition: Matrix.cpp:902
kkint32 NumOfRows() const
Definition: Matrix.h:128
Matrix & operator=(const Matrix &right)
Definition: Matrix.cpp:329
__int32 kkint32
Definition: KKBaseTypes.h:88
VectorDouble GetCol(kkint32 col) const
Definition: Matrix.cpp:891
Matrix operator-(double right)
Definition: Matrix.cpp:443
Matrix operator+(double right)
Definition: Matrix.cpp:519
void osWaitForEnter()
#define SQR(X)
Matrix(kkint32 _numOfRows, kkint32 _numOfCols)
Definition: Matrix.cpp:108
Supports two dimensional matrices.
Definition: Matrix.h:46
static MatrixPtr BuildFromArray(kkint32 numOfRows, kkint32 numOfCols, T **data)
Will create a new matrix using the 2dArray "data" for source.
Definition: Matrix.cpp:190
Matrix(const Matrix &_matrix)
Definition: Matrix.cpp:142
~Row()
Definition: Matrix.cpp:59
Matrix * MatrixPtr
Definition: Matrix.h:49
Matrix & operator=(const VectorDouble &right)
Definition: Matrix.cpp:337
MatrixPtr Covariance() const
Returns a Covariance matrix.
Definition: Matrix.cpp:1004
kkint32 NumOfCols() const
Definition: Matrix.h:126
double & operator[](kkint32 idx)
Definition: Matrix.cpp:76
Matrix operator*(const Matrix &right)
Definition: Matrix.cpp:478
double DeterminantSlow()
Recursive Implementation.
Definition: Matrix.cpp:286
void EigenVectors(MatrixPtr &eigenVectors, VectorDouble *&eigenValues) const
Will derive the Eigen vectors and values of the matrix.
Definition: Matrix.cpp:768
KKTHread * KKTHreadPtr
bool Symmetric() const
Definition: Matrix.cpp:688
Matrix(const VectorDouble &_v)
Definition: Matrix.cpp:157
void FindMaxValue(double &maxVal, kkint32 &row, kkint32 &col)
Locates the maximum value in a matrix along with the row and column that is located.
Definition: Matrix.cpp:818
Matrix operator+(const Matrix &right)
Definition: Matrix.cpp:369
Matrix & operator+=(const Matrix &right)
Definition: Matrix.cpp:396
Row(kkint32 _numOfCols, double *_cells)
Definition: Matrix.cpp:34
static KKStr Concat(const std::vector< std::string > &values)
Concatenates the list of &#39;std::string&#39; strings.
Definition: KKStr.cpp:1082
Matrix Inverse()
Definition: Matrix.cpp:731
unsigned short ushort
Unsigned short.
Definition: KKBaseTypes.h:79
Matrix & operator*=(double right)
Definition: Matrix.cpp:349
std::ostream &__cdecl operator<<(std::ostream &os, const KKStr &str)
Row(const Row &_row)
Definition: Matrix.cpp:51
const T SIGN(const T &a, const T &b)
Definition: Matrix.cpp:1196
Matrix operator-(const Matrix &right)
Definition: Matrix.cpp:419
double Determinant()
Definition: Matrix.cpp:945
void ReSize(kkint32 _numOfRows, kkint32 _numOfCols)
Definition: Matrix.cpp:224
Matrix operator-(double left, const Matrix &right)
Definition: Matrix.cpp:456
MatrixPtr CalcCoFactorMatrix()
Definition: Matrix.cpp:606
KKException(const KKStr &_exceptionStr)
Definition: KKException.cpp:45
void Define(kkint32 _numOfCols, double *_cells)
Definition: Matrix.cpp:66
Matrix & operator+=(double right)
Definition: Matrix.cpp:359
Matrix operator*(double right)
Definition: Matrix.cpp:530
std::vector< double > VectorDouble
Vector of doubles.
Definition: KKBaseTypes.h:148