MathMatrix.cpp

00001 /*
00002  *  Copyright (C) 2010  Regents of the University of Michigan
00003  *
00004  *   This program is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include "MathMatrix.h"
00019 #include "MathVector.h"
00020 #include "MathConstant.h"
00021 #include "Sort.h"
00022 #include "Error.h"
00023 
00024 #include <string.h>
00025 #include <math.h>
00026 #include <stdio.h>
00027 
00028 int Matrix::alloc = 2;
00029 
00030 Matrix::~Matrix()
00031 {
00032     // printf("Deleting Matrix %s...\n", (const char *) label);
00033 
00034     for (int i=0; i<size; i++)
00035         delete data[i];
00036 
00037     if (size)
00038         delete [] data;
00039 
00040     if (extraSize)
00041         delete [] extras;
00042 }
00043 
00044 void Matrix::Init()
00045 {
00046     rows = cols = extraSize = size = 0;
00047     data = NULL;
00048     extras = NULL;
00049     label = "[Matrix]";
00050 }
00051 
00052 void Matrix::SetLabel(const char * name)
00053 {
00054     label = '[';
00055     label += name;
00056     label += ']';
00057 }
00058 
00059 void Matrix::Dimension(int m, int n)
00060 {
00061     if (n == cols && m == rows)
00062         return;
00063 
00064     if (n > extraSize)
00065     {
00066         int newSize = (n + alloc) / alloc  * alloc;
00067         ColumnExtras * newExtras = new ColumnExtras [newSize];
00068 
00069         if (extras != NULL)
00070             for (int i = 0; i < extraSize; i++)
00071                 newExtras[i] = extras[i];
00072 
00073         if (extraSize)
00074             delete [] extras;
00075 
00076         extraSize = newSize;
00077         extras = newExtras;
00078     }
00079 
00080     if (m > size)
00081     {
00082         int       newSize = (m + alloc) / alloc * alloc;
00083         Vector ** newData = new Vector * [newSize];
00084 
00085         if (data != NULL)
00086             for (int i = 0; i < size; i++)
00087                 newData[i] = data[i];
00088 
00089         for (int i = size; i < newSize; i++)
00090             newData[i] = new Vector(n);
00091 
00092         if (size)
00093             delete [] data;
00094 
00095         size = newSize;
00096         data = newData;
00097     }
00098 
00099     if (cols != n)
00100         for (int i = 0; i < rows; i++)
00101             data[i]->Dimension(n);
00102 
00103     if (rows != m)
00104         for (int i = rows; i < m; i++)
00105             data[i]->Dimension(n);
00106 
00107     rows = m;
00108     cols = n;
00109 }
00110 
00111 void Matrix::Dimension(int m, int n, double value)
00112 {
00113     int originalRows = rows;
00114     int originalColumns =  cols;
00115 
00116     Dimension(m, n);
00117 
00118     if (rows > originalRows)
00119         for (int i = originalRows; i < rows; i++)
00120             data[i]->Set(value);
00121 
00122     if (cols > originalColumns)
00123         for (int i = 0; i < originalRows; i++)
00124             for (int j = originalColumns; j < cols; j++)
00125                 data[i]->data[j] = value;
00126 }
00127 
00128 void Matrix::Zero()
00129 {
00130     for (int i = 0; i < rows; i++)
00131         for (int j = 0; j < cols; j++)
00132             (*(data[i]))[j] = 0.0;
00133 }
00134 
00135 void Matrix::Identity()
00136 {
00137     if (rows != cols)
00138         error("Matrix.Identity - Identity matrices must be square");
00139 
00140     for (int i = 0; i < rows; i++)
00141         for (int j = 0; j < cols; j++)
00142             if (i == j)
00143                 (*(data[i]))[j] = 1.0;
00144             else
00145                 (*(data[i]))[j] = 0.0;
00146 }
00147 
00148 void Matrix::Set(double k)
00149 {
00150     for (int i = 0; i < rows; i++)
00151         for (int j = 0; j < cols; j++)
00152             (*(data[i]))[j] = k;
00153 }
00154 
00155 void Matrix::Negate()
00156 {
00157     for (int i = 0; i < rows; i++)
00158         for (int j = 0; j < cols; j++)
00159             (*(data[i]))[j] = -(*(data[i]))[j];
00160 }
00161 
00162 void Matrix::Copy(const Matrix & m)
00163 {
00164     Dimension(m.rows, m.cols);
00165 
00166     if (m.data != NULL)
00167         for (int i = 0; i < rows; i++)
00168             for (int j = 0; j < cols; j++)
00169                 (*this)[i][j] = m[i][j];
00170 }
00171 
00172 void Matrix::Transpose(const Matrix & m)
00173 {
00174     Dimension(m.cols, m.rows);
00175 
00176     for (int i = 0; i < rows; i++)
00177         for (int j = 0; j < cols; j++)
00178             (*(data[i]))[j] = m[j][i];
00179 }
00180 
00181 void Matrix::Add(double k)
00182 {
00183     for (int i = 0; i < rows; i++)
00184         for (int j = 0; j < cols; j++)
00185             (*(data[i]))[j] += k;
00186 }
00187 
00188 void Matrix::Multiply(double k)
00189 {
00190     for (int i = 0; i < rows; i++)
00191         for (int j = 0; j < cols; j++)
00192             (*(data[i]))[j] *= k;
00193 }
00194 
00195 void Matrix::Add(const Matrix & m)
00196 {
00197     if ((rows != m.rows) && (cols != m.cols))
00198         error("Matrix.Add - Attempted to add incompatible matrices\n"
00199               "Matrices   - %s [%d, %d] + %s [%d, %d]\n",
00200               (const char  *) label, rows, cols,
00201               (const char  *) m.label, m.rows, m.cols);
00202 
00203     for (int i = 0; i < rows; i++)
00204         for (int j = 0; j < cols; j++)
00205             (*(data[i]))[j] += m[i][j];
00206 }
00207 
00208 void Matrix::AddMultiple(double k, const Matrix & m)
00209 {
00210     if ((rows != m.rows) && (cols != m.cols))
00211         error("Matrix.AddMultiple - Attempted to add incompatible matrices\n"
00212               "Matrices           - %s [%d, %d] + k * %s [%d, %d]\n",
00213               (const char  *) label, rows, cols,
00214               (const char  *) m.label, m.rows, m.cols);
00215 
00216     for (int i = 0; i < rows; i++)
00217         for (int j = 0; j < cols; j++)
00218             (*(data[i]))[j] += k * m[i][j];
00219 }
00220 
00221 
00222 void Matrix::Product(const Matrix & l, const Matrix & r)
00223 {
00224     if (l.cols != r.rows)
00225         error("Matrix.Multiply - Attempted to multiply incompatible matrices\n"
00226               "Matrices        - %s [%d, %d] + %s [%d, %d]\n",
00227               (const char  *) l.label, l.rows, l.cols,
00228               (const char  *) r.label, r.rows, r.cols);
00229 
00230     Dimension(l.rows, r.cols);
00231     Zero();
00232 
00233     for (int k = 0; k < l.cols; k++)
00234         for (int i = 0; i < rows; i++)
00235             for (int j = 0; j < cols; j++)
00236                 (*(data[i]))[j] += l[i][k] * r[k][j];
00237 }
00238 
00239 void Matrix::AddRows(double k, int r1, int r2)
00240 {
00241     Vector v(*(data[r1]));
00242 
00243     v.Multiply(k);
00244     data[r2]->Add(v);
00245 }
00246 
00247 void Matrix::MultiplyRow(int r1, double k)
00248 {
00249     data[r1]->Multiply(k);
00250 }
00251 
00252 void Matrix::AddRows(int r1, int r2)
00253 {
00254     data[r2]->Add(*(data[r1]));
00255 }
00256 
00257 void Matrix::Reduce(double tol)
00258 {
00259     double pivot;
00260     int pivotr = 0;      // Initializing pivotr is not necessary, but avoids warnings
00261     int r = 0;           // the row we are currently reducing
00262 
00263     for (int j = 0; j < cols; j++)
00264     {
00265         if (r > rows)
00266             return;
00267 
00268         pivot = 0.0;
00269         for (int i = r; i < rows; i++)
00270             if (fabs((*this)[i][j]) > pivot)
00271             {
00272                 pivot = fabs((*this)[i][j]);
00273                 pivotr = i;
00274             }
00275 
00276         if (pivot <= tol)
00277         {
00278             for (int i = r; i < rows; i++)
00279                 (*this)[i][j] = 0.0;
00280             continue;
00281         }
00282 
00283         SwapRows(pivotr, r);
00284 
00285         double scale = (*this)[r][j];
00286 
00287         (*this)[r][j] = 1.0;
00288         for (int k = j+1; k < cols; k++)
00289             (*this)[r][k] /= scale;
00290 
00291         for (int i = r + 1; r < rows; i++)
00292         {
00293             scale = (*this)[i][j];
00294             (*this)[i][j] = 0.0;
00295             for (int k = j+1; k < cols; k++)
00296                 (*this)[i][k] -= (*this)[r][k] * scale;
00297         }
00298 
00299         r++;
00300     }
00301 }
00302 
00303 void Matrix::DeleteRow(int r)
00304 {
00305     Vector * temp = data[r];
00306 
00307     for (int i = r + 1; i < rows; i++)
00308         data[i-1] = data[i];
00309 
00310     data[rows - 1] = temp;
00311     rows--;
00312 }
00313 
00314 void Matrix::DeleteColumn(int c)
00315 {
00316     for (int i = 0; i < rows; i++)
00317         data[i] -> DeleteDimension(c);
00318 
00319     for (int i = c + 1; i < cols; i++)
00320         extras[i-1] = extras[i];
00321 
00322     cols--;
00323 }
00324 
00325 void Matrix::SwapColumns(int c1, int c2)
00326 {
00327     double temp;
00328 
00329     for (int i = 0; i < rows; i++)
00330     {
00331         temp = (*data[i])[c1];
00332         (*data[i])[c1] = (*data[i])[c2];
00333         (*data[i])[c2] = temp;
00334     }
00335 
00336     extras[c1].Swap(extras[c2]);
00337 }
00338 
00339 void Matrix::Read(FILE * f)
00340 {
00341     int  r, c;
00342     char buffer[100];
00343 
00344     fscanf(f, " %s =", buffer);
00345     buffer[strlen(buffer) - 1] = 0;
00346     SetLabel(buffer);
00347 
00348     fscanf(f, " [ %d x %d ]", &r, &c);
00349     Dimension(r, c);
00350 
00351     for (int c = 0; c < cols; c++)
00352     {
00353         fscanf(f, " %s", buffer);
00354         SetColumnLabel(c, buffer);
00355     }
00356 
00357     for (int r = 0; r < rows; r++)
00358         for (int c = 0; c < cols; c++)
00359             fscanf(f, " %lf", &((*this)[r][c]));
00360 }
00361 
00362 
00363 void Matrix::Print(FILE * f, int r, int c)
00364 {
00365     if (r == -1 || r > rows) r = rows;
00366     if (c == -1 || c > cols) c = cols;
00367 
00368     char dimensions[30];
00369 
00370     sprintf(dimensions, "[%d x %d]", r, c);
00371 
00372     int columnZero = label.Length() > 15 ? label.Length() : 15;
00373 
00374     fprintf(f, "\n%*s =\n%*s ", columnZero, (const char  *) label,
00375             columnZero, dimensions);
00376 
00377     int * precision = new int [c + 1];
00378     int * width = new int [c + 1];
00379 
00380     for (int j = 0; j < c; j++)
00381     {
00382         precision[j] = extras[j].GetPrecision();
00383         width[j] = extras[j].GetWidth();
00384         fprintf(f, "%*s ", width[j], (const char  *) extras[j].label);
00385     }
00386 
00387     for (int i = 0; i < r; i++)
00388     {
00389         fprintf(f, "\n%*s ", columnZero, (const char  *) data[i]->label);
00390         for (int j = 0; j < c; j++)
00391             fprintf(f, "%*.*f ", width[j], precision[j], (*this)[i][j]);
00392     }
00393 
00394     fprintf(f, "\n");
00395 
00396     delete [] precision;
00397     delete [] width;
00398 }
00399 
00400 void Matrix::CopyLabels(Matrix & M)
00401 {
00402     for (int i = 0; i < rows; i++)
00403         if (i < M.rows)
00404             data[i]->SetLabel(M[i].label);
00405 
00406     for (int i = 0; i < cols; i++)
00407         if (i < M.cols)
00408             SetColumnLabel(i, M.GetColumnLabel(i));
00409 }
00410 
00411 // ColumnExtras class
00412 //
00413 
00414 void ColumnExtras::Init()
00415 {
00416     label = "column";
00417     dirty = true;
00418     precision = 3;
00419     width = 7;
00420 }
00421 
00422 ColumnExtras::~ColumnExtras()
00423 { }
00424 
00425 void ColumnExtras::SetLabel(const char * name)
00426 {
00427     label = name;
00428 }
00429 
00430 int ColumnExtras::GetWidth()
00431 {
00432     if (dirty)
00433     {
00434         if (precision + 2 > width)
00435             width = precision + 2;
00436         if (label.Length() > width)
00437             width = label.Length();
00438         dirty = false;
00439     }
00440     return width;
00441 }
00442 
00443 void ColumnExtras::Copy(ColumnExtras & c)
00444 {
00445     width = c.width;
00446     precision = c.precision;
00447     dirty = c.dirty;
00448     label = c.label;
00449 }
00450 
00451 #define SWAP(a,b)      {int swap=(a); (a)=(b); (b)=swap;}
00452 #define SWAPBOOL(a,b)  {bool swap=(a); (a)=(b); (b)=swap;}
00453 
00454 void ColumnExtras::Swap(ColumnExtras & c)
00455 {
00456     SWAP(c.width, width);
00457     SWAP(c.precision, precision);
00458     SWAPBOOL(c.dirty, dirty);
00459     c.label.Swap(label);
00460 }
00461 
00462 int Matrix::CompareRows(Vector ** row1, Vector ** row2)
00463 {
00464     if ((**row1)[0] < (**row2)[0]) return -1;
00465     if ((**row1)[0] > (**row2)[0]) return 1;
00466     return 0;
00467 }
00468 
00469 void Matrix::Sort()
00470 {
00471     QuickSort(data, rows, sizeof(Vector *), COMPAREFUNC CompareRows);
00472 }
00473 
00474 bool Matrix::operator == (const Matrix & rhs) const
00475 {
00476     if (rhs.rows != rows || rhs.cols != cols) return false;
00477 
00478     for (int i = 0; i < rows; i++)
00479         if ((*this)[i] != rhs[i])
00480             return false;
00481     return true;
00482 }
00483 
00484 void Matrix::StackBottom(const Matrix & m)
00485 {
00486     if (m.cols != cols)
00487         error("Attempted to stack matrices with different number of columns");
00488 
00489     int end = rows;
00490 
00491     Dimension(rows + m.rows, cols);
00492 
00493     for (int i = 0; i < m.rows; i++)
00494         *(data[i + end]) = m[i];
00495 }
00496 
00497 void Matrix::StackLeft(const Matrix & m)
00498 {
00499     if (m.rows != rows)
00500         error("Attempted to stack matrics with different numbers of rows");
00501 
00502     for (int i = 0; i < rows; i++)
00503         data[i]->Stack(m[i]);
00504 
00505     Dimension(rows, cols + m.cols);
00506 }
00507 
00508 void Matrix::Swap(Matrix & m)
00509 {
00510     label.Swap(m.label);
00511 
00512     ColumnExtras * tmpExtras = extras;
00513     extras = m.extras;
00514     m.extras = tmpExtras;
00515 
00516     int swap;
00517     swap = rows;
00518     rows = m.rows;
00519     m.rows = swap;
00520     swap = cols;
00521     cols = m.cols;
00522     m.cols = swap;
00523     swap = size;
00524     size = m.size;
00525     m.size = swap;
00526     swap = extraSize;
00527     extraSize = m.extraSize;
00528     m.extraSize = swap;
00529 
00530     Vector ** tmpData = data;
00531     data = m.data;
00532     m.data = tmpData;
00533 }
00534 
00535 double Matrix::Min() const
00536 {
00537     if (rows == 0 || cols == 0)
00538         return 0.0;
00539 
00540     double minimum = data[0]->Min();
00541 
00542     for (int i = 1; i < rows; i++)
00543         minimum = min(data[i]->Min(), minimum);
00544 
00545     return minimum;
00546 }
00547 
00548 double Matrix::Max() const
00549 {
00550     if (rows == 0 || cols == 0)
00551         return 0.0;
00552 
00553     double maximum = data[0]->Max();
00554 
00555     for (int i = 1; i < rows; i++)
00556         maximum = max(data[i]->Max(), maximum);
00557 
00558     return maximum;
00559 }
00560 
00561 double Matrix::Mean() const
00562 {
00563     if (rows == 0 || cols == 0)
00564         return 0.0;
00565 
00566     double sum = data[0]->Sum();
00567 
00568     for (int i = 1; i < rows; i++)
00569         sum += data[i]->Sum();
00570 
00571     return sum / (rows * cols);
00572 }
00573 
00574 double Matrix::SafeMin() const
00575 {
00576     double lo = (rows > 0 && cols > 0) ? _NAN_ : 0.0;
00577 
00578     int i, j;
00579 
00580     for (i = 0; i < rows; i++)
00581     {
00582         for (j = 0; j < cols; j++)
00583             if (data[i]->data[j] != _NAN_)
00584             {
00585                 lo = data[i]->data[j];
00586                 break;
00587             }
00588         if (j != cols) break;
00589     }
00590 
00591     for (; i < rows; i++, j = 0)
00592         for (; j < cols; j++)
00593             if (data[i]->data[j] < lo && data[i]->data[j] != _NAN_)
00594                 lo = data[i]->data[j];
00595 
00596     return lo;
00597 }
00598 
00599 double Matrix::SafeMax() const
00600 {
00601     double hi = (rows > 0 && cols > 0) ? _NAN_ : 0.0;
00602 
00603     int i, j;
00604 
00605     for (i = 0; i < rows; i++)
00606     {
00607         for (j = 0; j < cols; j++)
00608             if (data[i]->data[j] != _NAN_)
00609             {
00610                 hi = data[i]->data[j];
00611                 break;
00612             }
00613         if (j != cols) break;
00614     }
00615 
00616     for (; i < rows; i++, j = 0)
00617         for (; j < cols; j++)
00618             if (data[i]->data[j] > hi && data[i]->data[j] != _NAN_)
00619                 hi = data[i]->data[j];
00620 
00621     return hi;
00622 }
00623 
00624 double Matrix::SafeMean() const
00625 {
00626     double sum = 0.0;
00627     int count = 0;
00628 
00629     for (int i = 0; i < rows; i++)
00630         for (int j = 0; j < cols; j++)
00631             if ((*this)[i][j] != _NAN_)
00632             {
00633                 sum += (*this)[i][j];
00634                 count ++;
00635             }
00636 
00637     return (count) ? sum / count : 0.0;
00638 }
00639 
00640 int Matrix::SafeCount() const
00641 {
00642     int total = 0;
00643 
00644     for (int i = 0; i < rows; i++)
00645         total += data[i]->SafeCount();
00646 
00647     return total;
00648 }
00649 
00650 void Matrix::PrintUpper(FILE * f, int r, int c, bool print_diag)
00651 {
00652     int columnZero;
00653     int * precision = NULL, * width = NULL; // Initialization avoids compiler warnings
00654 
00655     SetupPrint(f, r, c, columnZero, precision, width);
00656 
00657     int upper = print_diag ? 0 : 1;
00658     for (int i = 0; i < r ; i++)
00659     {
00660         fprintf(f, "\n%*s ", columnZero, (const char  *) data[i]->label);
00661 
00662         for (int j = 0; j < upper; j++)
00663             fprintf(f, "%*.*s ", width[j], precision[j], " ");
00664         for (int j = upper; j < c; j++)
00665             fprintf(f, "%*.*f ", width[j], precision[j], (*this)[i][j]);
00666 
00667         upper++;
00668     }
00669 
00670     fprintf(f, "\n");
00671 
00672     delete [] precision;
00673     delete [] width;
00674 }
00675 
00676 void Matrix::PrintLower(FILE * f, int r, int c, bool print_diag)
00677 {
00678     if (r == -1 || r > rows) r = rows;
00679     if (c == -1 || c > cols) c = cols;
00680 
00681     String dimensions;
00682     dimensions.printf("[%d x %d]", r, c);
00683 
00684     int columnZero = label.Length() > 15 ? label.Length() : 15;
00685 
00686     fprintf(f, "\n%*s =\n%*s ", columnZero, (const char  *) label,
00687             columnZero, (const char *) dimensions);
00688 
00689     int * precision = new int [c + 1];
00690     int * width = new int [c + 1];
00691 
00692     for (int j = 0; j < c; j++)
00693     {
00694         precision[j] = extras[j].GetPrecision();
00695         width[j] = extras[j].GetWidth();
00696         fprintf(f, "%*s ", width[j], (const char  *) extras[j].label);
00697     }
00698 
00699     int upper = print_diag ? 1 : 0;
00700 
00701     for (int i = 0; i < r ; i++)
00702     {
00703         fprintf(f, "\n%*s ", columnZero, (const char  *) data[i]->label);
00704         for (int j = 0; j < upper; j++)
00705             fprintf(f, "%*.*f ", width[j], precision[j],(*this)[i][j]);
00706         for (int j = upper; j < c; j++)
00707             fprintf(f, "%*.*s ", width[j], precision[j]," ");
00708 
00709         upper++;
00710     }
00711 
00712     fprintf(f, "\n");
00713 
00714     delete [] precision;
00715     delete [] width;
00716 }
00717 
00718 
00719 void Matrix::SetupPrint(FILE *f, int r, int c, int & column_zero, int * precision, int * width)
00720 {
00721     if (r == -1 || r > rows) r = rows;
00722     if (c == -1 || c > cols) c = cols;
00723 
00724     String dimensions;
00725     dimensions.printf("[%d x %d]", r, c);
00726 
00727     column_zero = label.Length() > 15 ? label.Length() : 15;
00728 
00729     fprintf(f, "\n%*s =\n%*s ", column_zero, (const char  *) label,
00730             column_zero, (const char *) dimensions);
00731 
00732     precision = new int [c + 1];
00733     width = new int [c + 1];
00734 
00735     for (int j = 0; j < c; j++)
00736     {
00737         precision[j] = extras[j].GetPrecision();
00738         width[j] = extras[j].GetWidth();
00739         fprintf(f, "%*s ", width[j], (const char  *) extras[j].label);
00740     }
00741 }
Generated on Wed Nov 17 15:38:29 2010 for StatGen Software by  doxygen 1.6.3