GestureRecognitionToolkit  Version: 1.0 Revision: 04-03-15
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
MatrixDouble.cpp
1 /*
2 GRT MIT License
3 Copyright (c) <2012> <Nicholas Gillian, Media Lab, MIT>
4 
5 Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6 and associated documentation files (the "Software"), to deal in the Software without restriction,
7 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all copies or substantial
12 portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 */
20 
21 #include "MatrixDouble.h"
22 
23 namespace GRT{
24 
26  warningLog.setProceedingText("[WARNING MatrixDouble]");
27  errorLog.setProceedingText("[ERROR MatrixDouble]");
28  this->dataPtr = NULL;
29  this->rows = 0;
30  this->cols = 0;
31 }
32 
33 MatrixDouble::MatrixDouble(const unsigned int rows,const unsigned int cols){
34  warningLog.setProceedingText("[WARNING MatrixDouble]");
35  errorLog.setProceedingText("[ERROR MatrixDouble]");
36  this->dataPtr = NULL;
37  if( rows > 0 && cols > 0 ){
38  resize(rows, cols);
39  }
40 }
41 
43  warningLog.setProceedingText("[WARNING MatrixDouble]");
44  errorLog.setProceedingText("[ERROR MatrixDouble]");
45  this->dataPtr = NULL;
46  this->rowPtr = NULL;
47  this->copy( rhs );
48 }
49 
51  warningLog.setProceedingText("[WARNING MatrixDouble]");
52  errorLog.setProceedingText("[ERROR MatrixDouble]");
53  this->dataPtr = NULL;
54  this->rowPtr = NULL;
55  this->copy( rhs );
56 }
57 
59  clear();
60 }
61 
63  if( this != &rhs ){
64  this->clear();
65  this->copy( rhs );
66  }
67  return *this;
68 }
69 
71  if( this != &rhs ){
72  this->clear();
73  this->copy( rhs );
74  }
75  return *this;
76 }
77 
78 MatrixDouble& MatrixDouble::operator=(const vector< VectorDouble > &rhs){
79 
80  clear();
81 
82  if( rhs.size() == 0 ) return *this;
83 
84  unsigned int M = (unsigned int)rhs.size();
85  unsigned int N = (unsigned int)rhs[0].size();
86  resize(M, N);
87 
88  for(unsigned int i=0; i<M; i++){
89  if( rhs[i].size() != N ){
90  clear();
91  return *this;
92  }
93  for(unsigned int j=0; j<N; j++){
94  dataPtr[i*cols+j] = rhs[i][j];
95  }
96  }
97 
98  return *this;
99 }
100 
101  /*
102 bool MatrixDouble::resize(const unsigned int rows,const unsigned int cols){
103  return Matrix<double>::resize(rows, cols);
104 }
105  */
106 
107 bool MatrixDouble::print(const string title) const {
108 
109  if( dataPtr == NULL ) return false;
110 
111  if( title != "" ){
112  std::cout << title << endl;
113  }
114  for(unsigned int i=0; i<rows; i++){
115  for(unsigned int j=0; j<cols; j++){
116  std::cout << dataPtr[i*cols+j] << "\t";
117  }
118  std::cout << std::endl;
119  }
120 
121  return true;
122 }
123 
125 
126  if( dataPtr == NULL ) return false;
127 
128  MatrixDouble temp(cols,rows);
129  for(unsigned int i=0; i<rows; i++){
130  for(unsigned int j=0; j<cols; j++){
131  temp[j][i] = dataPtr[i*cols+j];
132  }
133  }
134 
135  *this = temp;
136 
137  return true;
138 }
139 
140 bool MatrixDouble::scale(const double minTarget,const double maxTarget){
141 
142  if( dataPtr == NULL ) return false;
143 
144  vector< MinMax > ranges = getRanges();
145 
146  return scale(ranges,minTarget,maxTarget);
147 }
148 
149 bool MatrixDouble::scale(const vector< MinMax > &ranges,const double minTarget,const double maxTarget){
150  if( dataPtr == NULL ) return false;
151 
152  if( ranges.size() != cols ){
153  return false;
154  }
155 
156  unsigned int i,j = 0;
157  for(i=0; i<rows; i++){
158  for(j=0; j<cols; j++){
159  dataPtr[i*cols+j] = Util::scale(dataPtr[i*cols+j],ranges[j].minValue,ranges[j].maxValue,minTarget,maxTarget);
160  }
161  }
162  return true;
163 }
164 
165 bool MatrixDouble::znorm(const double alpha){
166  if( dataPtr == NULL ) return false;
167 
168  UINT i,j = 0;
169  double mean, std = 0;
170  for(i=0; i<rows; i++){
171  mean = 0;
172  std = 0;
173 
174  //Compute the mean
175  for(j=0; j<cols; j++){
176  mean += dataPtr[i*cols+j];
177  }
178  mean /= cols;
179 
180  //Compute the std dev
181  for(j=0; j<cols; j++){
182  std += (dataPtr[i*cols+j]-mean)*(dataPtr[i*cols+j]-mean);
183  }
184  std /= cols;
185  std = sqrt( std + alpha );
186 
187  //Normalize the row
188  for(j=0; j<cols; j++){
189  dataPtr[i*cols+j] = (dataPtr[i*cols+j]-mean) / std;
190  }
191  }
192 
193  return true;
194 }
195 
196 MatrixDouble MatrixDouble::multiple(const double value) const{
197 
198  if( dataPtr == NULL ) return MatrixDouble();
199 
201  double *d_p = &(d[0][0]);
202 
203  unsigned int i = 0;
204  for(i=0; i<rows*cols; i++){
205  d_p[i] = dataPtr[i] * value;
206  }
207 
208  return d;
209 }
210 
211 VectorDouble MatrixDouble::multiple(const VectorDouble &b) const{
212 
213  const unsigned int M = rows;
214  const unsigned int N = cols;
215  const unsigned int K = (unsigned int)b.size();
216 
217  if( N != K ){
218  warningLog << "multiple(vector b) - The size of b (" << b.size() << ") does not match the number of columns in this matrix (" << N << ")" << std::endl;
219  return VectorDouble();
220  }
221 
222  VectorDouble c(M);
223  const double *pb = &b[0];
224  double *pc = &c[0];
225 
226  unsigned int i,j = 0;
227  for(i=0; i<rows; i++){
228  pc[i] = 0;
229  for(j=0; j<cols; j++){
230  pc[i] += dataPtr[i*cols+j]*pb[j];
231  }
232  }
233 
234  return c;
235 }
236 
238 
239  const unsigned int M = rows;
240  const unsigned int N = cols;
241  const unsigned int K = b.getNumRows();
242  const unsigned int L = b.getNumCols();
243 
244  if( N != K ) {
245  errorLog << "multiple(MatrixDouble b) - The number of rows in b (" << K << ") does not match the number of columns in this matrix (" << N << ")" << std::endl;
246  return MatrixDouble();
247  }
248 
249  MatrixDouble c(M,L);
250  double **pb = b.getDataPointer();
251  double **pc = c.getDataPointer();
252 
253  unsigned int i,j,k = 0;
254  for(i=0; i<M; i++){
255  for(j=0; j<L; j++){
256  pc[i][j] = 0;
257  for(k=0; k<K; k++){
258  pc[i][j] += dataPtr[i*cols+k] * pb[k][j];
259  }
260  }
261  }
262 
263  return c;
264 }
265 
266 bool MatrixDouble::multiple(const MatrixDouble &a,const MatrixDouble &b,const bool aTranspose){
267 
268  const unsigned int M = !aTranspose ? a.getNumRows() : a.getNumCols();
269  const unsigned int N = !aTranspose ? a.getNumCols() : a.getNumRows();
270  const unsigned int K = b.getNumRows();
271  const unsigned int L = b.getNumCols();
272 
273  if( N != K ) {
274  errorLog << "multiple(const MatrixDouble &a,const MatrixDouble &b,const bool aTranspose) - The number of rows in a (" << K << ") does not match the number of columns in matrix b (" << N << ")" << std::endl;
275  return false;
276  }
277 
278  if( !resize( M, L ) ){
279  errorLog << "multiple(const MatrixDouble &b,const MatrixDouble &c,const bool bTranspose) - Failed to resize matrix!" << endl;
280  return false;
281  }
282 
283  unsigned int i, j, k = 0;
284 
285  //Using direct pointers really helps speed up the computation time
286  double **pa = a.getDataPointer();
287  double **pb = b.getDataPointer();
288 
289  if( aTranspose ){
290 
291  for(j=0; j<L; j++){
292  for(i=0; i<M; i++){
293  dataPtr[i*cols+j] = 0;
294  for(k=0; k<K; k++){
295  dataPtr[i*cols+j] += pa[k][i] * pb[k][j];
296  }
297  }
298  }
299 
300  }else{
301 
302  for(j=0; j<L; j++){
303  for(i=0; i<M; i++){
304  dataPtr[i*cols+j] = 0;
305  for(k=0; k<K; k++){
306  dataPtr[i*cols+j] += pa[i][k] * pb[k][j];
307  }
308  }
309  }
310 
311  }
312 
313  return true;
314 }
315 
317 
318  if( b.getNumRows() != rows ){
319  errorLog << "add(const MatrixDouble &b) - Failed to add matrix! The rows do not match!" << endl;
320  return false;
321  }
322 
323  if( b.getNumCols() != cols ){
324  errorLog << "add(const MatrixDouble &b) - Failed to add matrix! The rows do not match!" << endl;
325  return false;
326  }
327 
328  unsigned int i = 0;
329 
330  //Using direct pointers really helps speed up the computation time
331  const double *p_b = &(b[0][0]);
332 
333  for(i=0; i<rows*cols; i++){
334  dataPtr[i] += p_b[i];
335  }
336 
337  return true;
338 }
339 
341 
342  const unsigned int M = a.getNumRows();
343  const unsigned int N = a.getNumCols();
344 
345  if( M != b.getNumRows() ){
346  errorLog << "add(const MatrixDouble &a,const MatrixDouble &b) - Failed to add matrix! The rows do not match!";
347  errorLog << " a rows: " << M << " b rows: " << b.getNumRows() << endl;
348  return false;
349  }
350 
351  if( N != b.getNumCols() ){
352  errorLog << "add(const MatrixDouble &a,const MatrixDouble &b) - Failed to add matrix! The columns do not match!";
353  errorLog << " a cols: " << N << " b cols: " << b.getNumCols() << endl;
354  return false;
355  }
356 
357  resize( M, N );
358 
359  UINT i,j;
360 
361  //Using direct pointers really helps speed up the computation time
362  double **pa = a.getDataPointer();
363  double **pb = b.getDataPointer();
364 
365  for(i=0; i<M; i++){
366  for(j=0; j<N; j++){
367  dataPtr[i*cols+j] = pa[i][j] + pb[i][j];
368  }
369  }
370 
371  return true;
372 }
373 
375 
376  if( b.getNumRows() != rows ){
377  errorLog << "subtract(const MatrixDouble &b) - Failed to add matrix! The rows do not match!" << endl;
378  errorLog << " rows: " << rows << " b rows: " << b.getNumRows() << endl;
379  return false;
380  }
381 
382  if( b.getNumCols() != cols ){
383  errorLog << "subtract(const MatrixDouble &b) - Failed to add matrix! The rows do not match!" << endl;
384  errorLog << " cols: " << cols << " b cols: " << b.getNumCols() << endl;
385  return false;
386  }
387 
388  unsigned int i,j;
389 
390  //Using direct pointers really helps speed up the computation time
391  double **pb = b.getDataPointer();
392 
393  for(i=0; i<rows; i++){
394  for(j=0; j<cols; j++){
395  dataPtr[i*cols+j] -= pb[i][j];
396  }
397  }
398 
399  return true;
400 }
401 
403 
404  const unsigned int M = a.getNumRows();
405  const unsigned int N = a.getNumCols();
406 
407  if( M != b.getNumRows() ){
408  errorLog << "subtract(const MatrixDouble &a,const MatrixDouble &b) - Failed to add matrix! The rows do not match!";
409  errorLog << " a rows: " << M << " b rows: " << b.getNumRows() << endl;
410  return false;
411  }
412 
413  if( N != b.getNumCols() ){
414  errorLog << "subtract(const MatrixDouble &a,const MatrixDouble &b) - Failed to add matrix! The columns do not match!";
415  errorLog << " a cols: " << N << " b cols: " << b.getNumCols() << endl;
416  return false;
417  }
418 
419  resize( M, N );
420 
421  UINT i,j;
422 
423  //Using direct pointers really helps speed up the computation time
424  double **pa = a.getDataPointer();
425  double **pb = b.getDataPointer();
426 
427  for(i=0; i<M; i++){
428  for(j=0; j<N; j++){
429  dataPtr[i*cols+j] = pa[i][j] - pb[i][j];
430  }
431  }
432 
433  return true;
434 }
435 
437  double minValue = 99e+99;
438  for(unsigned int i=0; i<rows*cols; i++){
439  if( dataPtr[i] < minValue ) minValue = dataPtr[i];
440  }
441  return minValue;
442 }
443 
445  double maxValue = 99e-99;
446  for(unsigned int i=0; i<rows*cols; i++){
447  if( dataPtr[i] > maxValue ) maxValue = dataPtr[i];
448  }
449  return maxValue;
450 }
451 
452 VectorDouble MatrixDouble::getMean() const{
453 
454  VectorDouble mean(cols);
455 
456  for(unsigned int c=0; c<cols; c++){
457  mean[c] = 0;
458  for(unsigned int r=0; r<rows; r++){
459  mean[c] += dataPtr[r*cols+c];
460  }
461  mean[c] /= double( rows );
462  }
463 
464  return mean;
465 }
466 
467 VectorDouble MatrixDouble::getStdDev() const{
468 
469  VectorDouble mean = getMean();
470  VectorDouble stdDev(cols,0);
471 
472  for(unsigned int j=0; j<cols; j++){
473  for(unsigned int i=0; i<rows; i++){
474  stdDev[j] += (dataPtr[i*cols+j]-mean[j])*(dataPtr[i*cols+j]-mean[j]);
475  }
476  stdDev[j] = sqrt( stdDev[j] / double(rows-1) );
477  }
478  return stdDev;
479 }
480 
482 
483  vector<double> mean = getMean();
484  MatrixDouble covMatrix(cols,cols);
485 
486  for(unsigned int j=0; j<cols; j++){
487  for(unsigned int k=0; k<cols; k++){
488  covMatrix[j][k] = 0;
489  for(unsigned int i=0; i<rows; i++){
490  covMatrix[j][k] += (dataPtr[i*cols+j]-mean[j]) * (dataPtr[i*cols+k]-mean[k]);
491  }
492  covMatrix[j][k] /= double(rows-1);
493  }
494  }
495 
496  return covMatrix;
497 }
498 
499 std::vector< MinMax > MatrixDouble::getRanges() const{
500 
501  if( rows == 0 ) return std::vector< MinMax >();
502 
503  vector< MinMax > ranges(cols);
504  for(unsigned int i=0; i<rows; i++){
505  for(unsigned int j=0; j<cols; j++){
506  ranges[j].updateMinMax( dataPtr[i*cols+j] );
507  }
508  }
509  return ranges;
510 }
511 
512 double MatrixDouble::getTrace() const{
513  double t = 0;
514  unsigned int K = (rows < cols ? rows : cols);
515  for(unsigned int i=0; i < K; i++) {
516  t += dataPtr[i*cols+i];
517  }
518  return t;
519 }
520 
521 bool MatrixDouble::save(const string &filename) const{
522 
523  std::fstream file;
524  file.open(filename.c_str(), std::ios::out);
525 
526  if( !file.is_open() ){
527  return false;
528  }
529 
530  for(UINT i=0; i<rows; i++){
531  for(UINT j=0; j<cols; j++){
532  file << dataPtr[i*cols+j] << (j<cols-1 ? "," : "\n");
533  }
534  }
535 
536  file.close();
537  return true;
538 }
539 
540 bool MatrixDouble::load(const string &filename,const char seperator){
541 
542  //Clear any previous data
543  clear();
544 
545  //Open the file
546  ifstream file( filename.c_str(), ifstream::in );
547  if ( !file.is_open() ){
548  warningLog << "parseFile(...) - Failed to open file: " << filename << endl;
549  return false;
550  }
551 
552  vector< string > vec;
553  vector< double > row;
554  string line;
555  string columnString = "";
556  const int sepValue = seperator;
557  unsigned int rowCounter = 0;
558  unsigned int columnCounter = 0;
559  unsigned int length = 0;
560 
561  //Count the number of columns in the first row
562  if( !getline(file,line) ){
563  warningLog << "parseFile(...) - Failed to read first row!" << endl;
564  return false;
565  }
566 
567  length = (unsigned int)line.length();
568  for(unsigned int i=0; i<length; i++){
569  if( int(line[i]) == sepValue ){
570  columnCounter++;
571  }
572  }
573  columnCounter++;
574 
575  //Count the number of rows in the file
576  rowCounter = 1;
577  while ( getline(file,line) ){
578  rowCounter++;
579  }
580 
581  //Assign the memory
582  if( !resize(rowCounter, columnCounter) ){
583  warningLog << "parseFile(...) - Failed to resize memory!" << endl;
584  return false;
585  }
586 
587  //Reset the file read pointer
588  file.close();
589  file.open( filename.c_str(), ifstream::in );
590  rowCounter = 0;
591 
592  //Loop over each line of data and parse the contents
593  while ( getline(file,line) )
594  {
595  //Scan the line contents for the seperator token and parse the contents between each token
596  vec.clear();
597  columnString = "";
598  length = (unsigned int)line.length();
599  for(unsigned int i=0; i<length; i++){
600  if( int(line[i]) == sepValue ){
601  vec.push_back( columnString );
602  columnString = "";
603  }else columnString += line[i];
604  }
605 
606  //Add the last column
607  vec.push_back( columnString );
608 
609  //Check to make sure all the columns are consistent
610  if( columnCounter != vec.size() ){
611  clear();
612  warningLog << "parseFile(...) - Found inconsistent column size in row " << rowCounter;
613  warningLog << " ColumnSize: " << columnCounter << " LastColumnSize: " << vec.size() << endl;
614  return false;
615  }
616 
617  //Remove the new line character from the string in the last column
618  if( vec.size() >= 1 ){
619  size_t K = vec.size()-1;
620  size_t foundA = vec[ K ].find('\n');
621  size_t foundB = vec[K ].find('\r');
622  if( foundA != std::string::npos || foundB != std::string::npos ){
623  vec[ K ] = vec[ K ].substr(0,vec[ K ].length()-1);
624  }
625  }
626 
627  //Convert the string column values to double values
628  for(unsigned int j=0; j<columnCounter; j++){
629  dataPtr[rowCounter*cols+j] = stringToDouble(vec[j]);
630  }
631  rowCounter++;
632  }
633 
634  //Close the file
635  file.close();
636 
637  return true;
638 }
639 
640 bool MatrixDouble::saveToCSVFile(const string &filename) const{
641  return save( filename );
642 }
643 
644 bool MatrixDouble::loadFromCSVFile(const string &filename,const char seperator){
645  return load( filename, seperator );
646 }
647 
648 }; //End of namespace GRT
MatrixDouble & operator=(const MatrixDouble &rhs)
virtual ~MatrixDouble()
Definition: AdaBoost.cpp:25
static double scale(const double &x, const double &minSource, const double &maxSource, const double &minTarget, const double &maxTarget, const bool constrain=false)
Definition: Util.cpp:44
bool subtract(const MatrixDouble &b)
unsigned int getNumCols() const
Definition: Matrix.h:538
bool load(const string &filename, const char seperator= ',')
double * dataPtr
A pointer to the raw data.
Definition: Matrix.h:573
T ** getDataPointer() const
Definition: Matrix.h:560
bool scale(const double minTarget, const double maxTarget)
double getTrace() const
bool loadFromCSVFile(const string &filename, const char seperator= ',')
VectorDouble getStdDev() const
bool save(const string &filename) const
bool saveToCSVFile(const string &filename) const
virtual bool copy(const Matrix< double > &rhs)
Definition: Matrix.h:308
MatrixDouble multiple(const double value) const
MatrixDouble getCovarianceMatrix() const
bool znorm(const double alpha=0.001)
unsigned int size
Stores rows * cols.
Definition: Matrix.h:571
bool add(const MatrixDouble &b)
double ** rowPtr
A pointer to each row in the data.
Definition: Matrix.h:574
unsigned int getNumRows() const
Definition: Matrix.h:531
double getMinValue() const
double getMaxValue() const
VectorDouble getMean() const
unsigned int rows
The number of rows in the Matrix.
Definition: Matrix.h:569
std::vector< MinMax > getRanges() const
unsigned int cols
The number of columns in the Matrix.
Definition: Matrix.h:570
virtual bool resize(const unsigned int r, const unsigned int c)
Definition: Matrix.h:234
bool print(const string title="") const