00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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;
00261 int r = 0;
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
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;
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 }