1 /*
2  *  Copyright (C) 2010  Regents of the University of Michigan
3  *
4  *   This program is free software: you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation, either version 3 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "MathMatrix.h"
19 #include "MathVector.h"
20 #include "MathConstant.h"
21 #include "Sort.h"
22 #include "Error.h"
23 
24 #include <string.h>
25 #include <math.h>
26 #include <stdio.h>
27 
28 int Matrix::alloc = 2;
29 
~Matrix()30 Matrix::~Matrix()
31 {
32     // printf("Deleting Matrix %s...\n", (const char *) label);
33 
34     for (int i=0; i<size; i++)
35         delete data[i];
36 
37     if (size)
38         delete [] data;
39 
40     if (extraSize)
41         delete [] extras;
42 }
43 
Init()44 void Matrix::Init()
45 {
46     rows = cols = extraSize = size = 0;
47     data = NULL;
48     extras = NULL;
49     label = "[Matrix]";
50 }
51 
SetLabel(const char * name)52 void Matrix::SetLabel(const char * name)
53 {
54     label = '[';
55     label += name;
56     label += ']';
57 }
58 
Dimension(int m,int n)59 void Matrix::Dimension(int m, int n)
60 {
61     if (n == cols && m == rows)
62         return;
63 
64     if (n > extraSize)
65     {
66         int newSize = (n + alloc) / alloc  * alloc;
67         ColumnExtras * newExtras = new ColumnExtras [newSize];
68 
69         if (extras != NULL)
70             for (int i = 0; i < extraSize; i++)
71                 newExtras[i] = extras[i];
72 
73         if (extraSize)
74             delete [] extras;
75 
76         extraSize = newSize;
77         extras = newExtras;
78     }
79 
80     if (m > size)
81     {
82         int       newSize = (m + alloc) / alloc * alloc;
83         Vector ** newData = new Vector * [newSize];
84 
85         if (data != NULL)
86             for (int i = 0; i < size; i++)
87                 newData[i] = data[i];
88 
89         for (int i = size; i < newSize; i++)
90             newData[i] = new Vector(n);
91 
92         if (size)
93             delete [] data;
94 
95         size = newSize;
96         data = newData;
97     }
98 
99     if (cols != n)
100         for (int i = 0; i < rows; i++)
101             data[i]->Dimension(n);
102 
103     if (rows != m)
104         for (int i = rows; i < m; i++)
105             data[i]->Dimension(n);
106 
107     rows = m;
108     cols = n;
109 }
110 
Dimension(int m,int n,double value)111 void Matrix::Dimension(int m, int n, double value)
112 {
113     int originalRows = rows;
114     int originalColumns =  cols;
115 
116     Dimension(m, n);
117 
118     if (rows > originalRows)
119         for (int i = originalRows; i < rows; i++)
120             data[i]->Set(value);
121 
122     if (cols > originalColumns)
123         for (int i = 0; i < originalRows; i++)
124             for (int j = originalColumns; j < cols; j++)
125                 data[i]->data[j] = value;
126 }
127 
Zero()128 void Matrix::Zero()
129 {
130     for (int i = 0; i < rows; i++)
131         for (int j = 0; j < cols; j++)
132             (*(data[i]))[j] = 0.0;
133 }
134 
Identity()135 void Matrix::Identity()
136 {
137     if (rows != cols)
138         error("Matrix.Identity - Identity matrices must be square");
139 
140     for (int i = 0; i < rows; i++)
141         for (int j = 0; j < cols; j++)
142             if (i == j)
143                 (*(data[i]))[j] = 1.0;
144             else
145                 (*(data[i]))[j] = 0.0;
146 }
147 
Set(double k)148 void Matrix::Set(double k)
149 {
150     for (int i = 0; i < rows; i++)
151         for (int j = 0; j < cols; j++)
152             (*(data[i]))[j] = k;
153 }
154 
Negate()155 void Matrix::Negate()
156 {
157     for (int i = 0; i < rows; i++)
158         for (int j = 0; j < cols; j++)
159             (*(data[i]))[j] = -(*(data[i]))[j];
160 }
161 
Copy(const Matrix & m)162 void Matrix::Copy(const Matrix & m)
163 {
164     Dimension(m.rows, m.cols);
165 
166     if (m.data != NULL)
167         for (int i = 0; i < rows; i++)
168             for (int j = 0; j < cols; j++)
169                 (*this)[i][j] = m[i][j];
170 }
171 
Transpose(const Matrix & m)172 void Matrix::Transpose(const Matrix & m)
173 {
174     Dimension(m.cols, m.rows);
175 
176     for (int i = 0; i < rows; i++)
177         for (int j = 0; j < cols; j++)
178             (*(data[i]))[j] = m[j][i];
179 }
180 
Add(double k)181 void Matrix::Add(double k)
182 {
183     for (int i = 0; i < rows; i++)
184         for (int j = 0; j < cols; j++)
185             (*(data[i]))[j] += k;
186 }
187 
Multiply(double k)188 void Matrix::Multiply(double k)
189 {
190     for (int i = 0; i < rows; i++)
191         for (int j = 0; j < cols; j++)
192             (*(data[i]))[j] *= k;
193 }
194 
Add(const Matrix & m)195 void Matrix::Add(const Matrix & m)
196 {
197     if ((rows != m.rows) && (cols != m.cols))
198         error("Matrix.Add - Attempted to add incompatible matrices\n"
199               "Matrices   - %s [%d, %d] + %s [%d, %d]\n",
200               (const char  *) label, rows, cols,
201               (const char  *) m.label, m.rows, m.cols);
202 
203     for (int i = 0; i < rows; i++)
204         for (int j = 0; j < cols; j++)
205             (*(data[i]))[j] += m[i][j];
206 }
207 
AddMultiple(double k,const Matrix & m)208 void Matrix::AddMultiple(double k, const Matrix & m)
209 {
210     if ((rows != m.rows) && (cols != m.cols))
211         error("Matrix.AddMultiple - Attempted to add incompatible matrices\n"
212               "Matrices           - %s [%d, %d] + k * %s [%d, %d]\n",
213               (const char  *) label, rows, cols,
214               (const char  *) m.label, m.rows, m.cols);
215 
216     for (int i = 0; i < rows; i++)
217         for (int j = 0; j < cols; j++)
218             (*(data[i]))[j] += k * m[i][j];
219 }
220 
221 
Product(const Matrix & l,const Matrix & r)222 void Matrix::Product(const Matrix & l, const Matrix & r)
223 {
224     if (l.cols != r.rows)
225         error("Matrix.Multiply - Attempted to multiply incompatible matrices\n"
226               "Matrices        - %s [%d, %d] + %s [%d, %d]\n",
227               (const char  *) l.label, l.rows, l.cols,
228               (const char  *) r.label, r.rows, r.cols);
229 
230     Dimension(l.rows, r.cols);
231     Zero();
232 
233     for (int k = 0; k < l.cols; k++)
234         for (int i = 0; i < rows; i++)
235             for (int j = 0; j < cols; j++)
236                 (*(data[i]))[j] += l[i][k] * r[k][j];
237 }
238 
AddRows(double k,int r1,int r2)239 void Matrix::AddRows(double k, int r1, int r2)
240 {
241     Vector v(*(data[r1]));
242 
243     v.Multiply(k);
244     data[r2]->Add(v);
245 }
246 
MultiplyRow(int r1,double k)247 void Matrix::MultiplyRow(int r1, double k)
248 {
249     data[r1]->Multiply(k);
250 }
251 
AddRows(int r1,int r2)252 void Matrix::AddRows(int r1, int r2)
253 {
254     data[r2]->Add(*(data[r1]));
255 }
256 
Reduce(double tol)257 void Matrix::Reduce(double tol)
258 {
259     double pivot;
260     int pivotr = 0;      // Initializing pivotr is not necessary, but avoids warnings
261     int r = 0;           // the row we are currently reducing
262 
263     for (int j = 0; j < cols; j++)
264     {
265         if (r > rows)
266             return;
267 
268         pivot = 0.0;
269         for (int i = r; i < rows; i++)
270             if (fabs((*this)[i][j]) > pivot)
271             {
272                 pivot = fabs((*this)[i][j]);
273                 pivotr = i;
274             }
275 
276         if (pivot <= tol)
277         {
278             for (int i = r; i < rows; i++)
279                 (*this)[i][j] = 0.0;
280             continue;
281         }
282 
283         SwapRows(pivotr, r);
284 
285         double scale = (*this)[r][j];
286 
287         (*this)[r][j] = 1.0;
288         for (int k = j+1; k < cols; k++)
289             (*this)[r][k] /= scale;
290 
291         for (int i = r + 1; r < rows; i++)
292         {
293             scale = (*this)[i][j];
294             (*this)[i][j] = 0.0;
295             for (int k = j+1; k < cols; k++)
296                 (*this)[i][k] -= (*this)[r][k] * scale;
297         }
298 
299         r++;
300     }
301 }
302 
DeleteRow(int r)303 void Matrix::DeleteRow(int r)
304 {
305     Vector * temp = data[r];
306 
307     for (int i = r + 1; i < rows; i++)
308         data[i-1] = data[i];
309 
310     data[rows - 1] = temp;
311     rows--;
312 }
313 
DeleteColumn(int c)314 void Matrix::DeleteColumn(int c)
315 {
316     for (int i = 0; i < rows; i++)
317         data[i] -> DeleteDimension(c);
318 
319     for (int i = c + 1; i < cols; i++)
320         extras[i-1] = extras[i];
321 
322     cols--;
323 }
324 
SwapColumns(int c1,int c2)325 void Matrix::SwapColumns(int c1, int c2)
326 {
327     double temp;
328 
329     for (int i = 0; i < rows; i++)
330     {
331         temp = (*data[i])[c1];
332         (*data[i])[c1] = (*data[i])[c2];
333         (*data[i])[c2] = temp;
334     }
335 
336     extras[c1].Swap(extras[c2]);
337 }
338 
Read(FILE * f)339 void Matrix::Read(FILE * f)
340 {
341     int  r, c;
342     char buffer[100];
343     int numItems = 0;
344 
345     numItems = fscanf(f, " %s =", buffer);
346     if(numItems != 1) { }
347     buffer[strlen(buffer) - 1] = 0;
348     SetLabel(buffer);
349 
350     numItems = fscanf(f, " [ %d x %d ]", &r, &c);
351     if(numItems != 2) { }
352     Dimension(r, c);
353 
354     for (int c = 0; c < cols; c++)
355     {
356         numItems = fscanf(f, " %s", buffer);
357         if(numItems != 1) { }
358         SetColumnLabel(c, buffer);
359     }
360 
361     for (int r = 0; r < rows; r++)
362         for (int c = 0; c < cols; c++)
363         {
364             numItems = fscanf(f, " %lf", &((*this)[r][c]));
365             if(numItems != 1) { }
366         }
367 }
368 
369 
Print(FILE * f,int r,int c)370 void Matrix::Print(FILE * f, int r, int c)
371 {
372     if (r == -1 || r > rows) r = rows;
373     if (c == -1 || c > cols) c = cols;
374 
375     char dimensions[30];
376 
377     sprintf(dimensions, "[%d x %d]", r, c);
378 
379     int columnZero = label.Length() > 15 ? label.Length() : 15;
380 
381     fprintf(f, "\n%*s =\n%*s ", columnZero, (const char  *) label,
382             columnZero, dimensions);
383 
384     int * precision = new int [c + 1];
385     int * width = new int [c + 1];
386 
387     for (int j = 0; j < c; j++)
388     {
389         precision[j] = extras[j].GetPrecision();
390         width[j] = extras[j].GetWidth();
391         fprintf(f, "%*s ", width[j], (const char  *) extras[j].label);
392     }
393 
394     for (int i = 0; i < r; i++)
395     {
396         fprintf(f, "\n%*s ", columnZero, (const char  *) data[i]->label);
397         for (int j = 0; j < c; j++)
398             fprintf(f, "%*.*f ", width[j], precision[j], (*this)[i][j]);
399     }
400 
401     fprintf(f, "\n");
402 
403     delete [] precision;
404     delete [] width;
405 }
406 
CopyLabels(Matrix & M)407 void Matrix::CopyLabels(Matrix & M)
408 {
409     for (int i = 0; i < rows; i++)
410         if (i < M.rows)
411             data[i]->SetLabel(M[i].label);
412 
413     for (int i = 0; i < cols; i++)
414         if (i < M.cols)
415             SetColumnLabel(i, M.GetColumnLabel(i));
416 }
417 
418 // ColumnExtras class
419 //
420 
Init()421 void ColumnExtras::Init()
422 {
423     label = "column";
424     dirty = true;
425     precision = 3;
426     width = 7;
427 }
428 
~ColumnExtras()429 ColumnExtras::~ColumnExtras()
430 { }
431 
SetLabel(const char * name)432 void ColumnExtras::SetLabel(const char * name)
433 {
434     label = name;
435 }
436 
GetWidth()437 int ColumnExtras::GetWidth()
438 {
439     if (dirty)
440     {
441         if (precision + 2 > width)
442             width = precision + 2;
443         if (label.Length() > width)
444             width = label.Length();
445         dirty = false;
446     }
447     return width;
448 }
449 
Copy(ColumnExtras & c)450 void ColumnExtras::Copy(ColumnExtras & c)
451 {
452     width = c.width;
453     precision = c.precision;
454     dirty = c.dirty;
455     label = c.label;
456 }
457 
458 #define SWAP(a,b)      {int swap=(a); (a)=(b); (b)=swap;}
459 #define SWAPBOOL(a,b)  {bool swap=(a); (a)=(b); (b)=swap;}
460 
Swap(ColumnExtras & c)461 void ColumnExtras::Swap(ColumnExtras & c)
462 {
463     SWAP(c.width, width);
464     SWAP(c.precision, precision);
465     SWAPBOOL(c.dirty, dirty);
466     c.label.Swap(label);
467 }
468 
CompareRows(Vector ** row1,Vector ** row2)469 int Matrix::CompareRows(Vector ** row1, Vector ** row2)
470 {
471     if ((**row1)[0] < (**row2)[0]) return -1;
472     if ((**row1)[0] > (**row2)[0]) return 1;
473     return 0;
474 }
475 
Sort()476 void Matrix::Sort()
477 {
478     QuickSort(data, rows, sizeof(Vector *), COMPAREFUNC CompareRows);
479 }
480 
operator ==(const Matrix & rhs) const481 bool Matrix::operator == (const Matrix & rhs) const
482 {
483     if (rhs.rows != rows || rhs.cols != cols) return false;
484 
485     for (int i = 0; i < rows; i++)
486         if ((*this)[i] != rhs[i])
487             return false;
488     return true;
489 }
490 
StackBottom(const Matrix & m)491 void Matrix::StackBottom(const Matrix & m)
492 {
493     if (m.cols != cols)
494         error("Attempted to stack matrices with different number of columns");
495 
496     int end = rows;
497 
498     Dimension(rows + m.rows, cols);
499 
500     for (int i = 0; i < m.rows; i++)
501         *(data[i + end]) = m[i];
502 }
503 
StackLeft(const Matrix & m)504 void Matrix::StackLeft(const Matrix & m)
505 {
506     if (m.rows != rows)
507         error("Attempted to stack matrics with different numbers of rows");
508 
509     for (int i = 0; i < rows; i++)
510         data[i]->Stack(m[i]);
511 
512     Dimension(rows, cols + m.cols);
513 }
514 
Swap(Matrix & m)515 void Matrix::Swap(Matrix & m)
516 {
517     label.Swap(m.label);
518 
519     ColumnExtras * tmpExtras = extras;
520     extras = m.extras;
521     m.extras = tmpExtras;
522 
523     int swap;
524     swap = rows;
525     rows = m.rows;
526     m.rows = swap;
527     swap = cols;
528     cols = m.cols;
529     m.cols = swap;
530     swap = size;
531     size = m.size;
532     m.size = swap;
533     swap = extraSize;
534     extraSize = m.extraSize;
535     m.extraSize = swap;
536 
537     Vector ** tmpData = data;
538     data = m.data;
539     m.data = tmpData;
540 }
541 
Min() const542 double Matrix::Min() const
543 {
544     if (rows == 0 || cols == 0)
545         return 0.0;
546 
547     double minimum = data[0]->Min();
548 
549     for (int i = 1; i < rows; i++)
550         minimum = min(data[i]->Min(), minimum);
551 
552     return minimum;
553 }
554 
Max() const555 double Matrix::Max() const
556 {
557     if (rows == 0 || cols == 0)
558         return 0.0;
559 
560     double maximum = data[0]->Max();
561 
562     for (int i = 1; i < rows; i++)
563         maximum = max(data[i]->Max(), maximum);
564 
565     return maximum;
566 }
567 
Mean() const568 double Matrix::Mean() const
569 {
570     if (rows == 0 || cols == 0)
571         return 0.0;
572 
573     double sum = data[0]->Sum();
574 
575     for (int i = 1; i < rows; i++)
576         sum += data[i]->Sum();
577 
578     return sum / (rows * cols);
579 }
580 
SafeMin() const581 double Matrix::SafeMin() const
582 {
583     double lo = (rows > 0 && cols > 0) ? _NAN_ : 0.0;
584 
585     int i, j;
586 
587     for (i = 0; i < rows; i++)
588     {
589         for (j = 0; j < cols; j++)
590             if (data[i]->data[j] != _NAN_)
591             {
592                 lo = data[i]->data[j];
593                 break;
594             }
595         if (j != cols) break;
596     }
597 
598     for (; i < rows; i++, j = 0)
599         for (; j < cols; j++)
600             if (data[i]->data[j] < lo && data[i]->data[j] != _NAN_)
601                 lo = data[i]->data[j];
602 
603     return lo;
604 }
605 
SafeMax() const606 double Matrix::SafeMax() const
607 {
608     double hi = (rows > 0 && cols > 0) ? _NAN_ : 0.0;
609 
610     int i, j;
611 
612     for (i = 0; i < rows; i++)
613     {
614         for (j = 0; j < cols; j++)
615             if (data[i]->data[j] != _NAN_)
616             {
617                 hi = data[i]->data[j];
618                 break;
619             }
620         if (j != cols) break;
621     }
622 
623     for (; i < rows; i++, j = 0)
624         for (; j < cols; j++)
625             if (data[i]->data[j] > hi && data[i]->data[j] != _NAN_)
626                 hi = data[i]->data[j];
627 
628     return hi;
629 }
630 
SafeMean() const631 double Matrix::SafeMean() const
632 {
633     double sum = 0.0;
634     int count = 0;
635 
636     for (int i = 0; i < rows; i++)
637         for (int j = 0; j < cols; j++)
638             if ((*this)[i][j] != _NAN_)
639             {
640                 sum += (*this)[i][j];
641                 count ++;
642             }
643 
644     return (count) ? sum / count : 0.0;
645 }
646 
SafeCount() const647 int Matrix::SafeCount() const
648 {
649     int total = 0;
650 
651     for (int i = 0; i < rows; i++)
652         total += data[i]->SafeCount();
653 
654     return total;
655 }
656 
PrintUpper(FILE * f,int r,int c,bool print_diag)657 void Matrix::PrintUpper(FILE * f, int r, int c, bool print_diag)
658 {
659     int columnZero;
660     int * precision = NULL, * width = NULL; // Initialization avoids compiler warnings
661 
662     SetupPrint(f, r, c, columnZero, precision, width);
663 
664     int upper = print_diag ? 0 : 1;
665     for (int i = 0; i < r ; i++)
666     {
667         fprintf(f, "\n%*s ", columnZero, (const char  *) data[i]->label);
668 
669         for (int j = 0; j < upper; j++)
670             fprintf(f, "%*.*s ", width[j], precision[j], " ");
671         for (int j = upper; j < c; j++)
672             fprintf(f, "%*.*f ", width[j], precision[j], (*this)[i][j]);
673 
674         upper++;
675     }
676 
677     fprintf(f, "\n");
678 
679     delete [] precision;
680     delete [] width;
681 }
682 
PrintLower(FILE * f,int r,int c,bool print_diag)683 void Matrix::PrintLower(FILE * f, int r, int c, bool print_diag)
684 {
685     if (r == -1 || r > rows) r = rows;
686     if (c == -1 || c > cols) c = cols;
687 
688     String dimensions;
689     dimensions.printf("[%d x %d]", r, c);
690 
691     int columnZero = label.Length() > 15 ? label.Length() : 15;
692 
693     fprintf(f, "\n%*s =\n%*s ", columnZero, (const char  *) label,
694             columnZero, (const char *) dimensions);
695 
696     int * precision = new int [c + 1];
697     int * width = new int [c + 1];
698 
699     for (int j = 0; j < c; j++)
700     {
701         precision[j] = extras[j].GetPrecision();
702         width[j] = extras[j].GetWidth();
703         fprintf(f, "%*s ", width[j], (const char  *) extras[j].label);
704     }
705 
706     int upper = print_diag ? 1 : 0;
707 
708     for (int i = 0; i < r ; i++)
709     {
710         fprintf(f, "\n%*s ", columnZero, (const char  *) data[i]->label);
711         for (int j = 0; j < upper; j++)
712             fprintf(f, "%*.*f ", width[j], precision[j],(*this)[i][j]);
713         for (int j = upper; j < c; j++)
714             fprintf(f, "%*.*s ", width[j], precision[j]," ");
715 
716         upper++;
717     }
718 
719     fprintf(f, "\n");
720 
721     delete [] precision;
722     delete [] width;
723 }
724 
725 
SetupPrint(FILE * f,int r,int c,int & column_zero,int * precision,int * width)726 void Matrix::SetupPrint(FILE *f, int r, int c, int & column_zero, int * precision, int * width)
727 {
728     if (r == -1 || r > rows) r = rows;
729     if (c == -1 || c > cols) c = cols;
730 
731     String dimensions;
732     dimensions.printf("[%d x %d]", r, c);
733 
734     column_zero = label.Length() > 15 ? label.Length() : 15;
735 
736     fprintf(f, "\n%*s =\n%*s ", column_zero, (const char  *) label,
737             column_zero, (const char *) dimensions);
738 
739     precision = new int [c + 1];
740     width = new int [c + 1];
741 
742     for (int j = 0; j < c; j++)
743     {
744         precision[j] = extras[j].GetPrecision();
745         width[j] = extras[j].GetWidth();
746         fprintf(f, "%*s ", width[j], (const char  *) extras[j].label);
747     }
748 }
749