00001
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <magic/mmath.h>
00028 #include <magic/mmatrix.h>
00029 #include <magic/mstream.h>
00030 #include <magic/mtextstream.h>
00031 #include <magic/mlist.h>
00032
00033 BEGIN_NAMESPACE (MagiC);
00034
00036
00037
00038
00039
00040
00042
00043
00044
00045
00046 Matrix::Matrix (
00047 int rows,
00048 int cols,
00049 double* pData)
00050 : PackTable<double> (rows, cols)
00051 {
00052 memcpy (mData, pData, rows*cols*sizeof(double));
00053 }
00054
00055 void Matrix::make (int rs, int cs)
00056 {
00057 PackTable<double>::make (rs, cs);
00058 operator= (0.0);
00059 }
00060
00065 void Matrix::load (const String& filename)
00066 {
00067 FILE* in = fopen (filename, "r");
00068 if (!in)
00069 throw file_not_found (format("Matrix file '%s' not found", (CONSTR)filename));
00070 load (in);
00071 fclose (in);
00072 }
00073
00078 void Matrix::load (FILE* in) {
00079 List<Vector*> rows;
00080
00081
00082 String buffer;
00083 String item;
00084 item.reserve (20);
00085
00086
00087 int rowCnt = 0;
00088 while (fgetS (in, buffer) != -1) {
00089 buffer.chop();
00090 Vector* prow = new Vector (cols);
00091 int itemIndex=0;
00092 for (uint i=0; i<buffer.length()+1; i++) {
00093 if (i==buffer.length() || buffer[i]==' ' || buffer[i]=='\t') {
00094 if (itemIndex<cols)
00095 (*prow)[itemIndex++] = (item=="x")? UNDEFINED_FLOAT : item.toDouble();
00096 item = "";
00097 } else
00098 item += buffer[i];
00099 }
00100 rows.add (prow);
00101 rowCnt++;
00102 }
00103
00104
00105 make (rowCnt,cols);
00106
00107
00108 int r=0;
00109 for (ListIter<Vector*> l (rows); !l.exhausted(); l.next(), r++) {
00110 for (int c=0; c<cols; c++)
00111 get(r,c) = (*l.get())[c];
00112 }
00113 }
00114
00115
00116
00117
00118 void Matrix::save (FILE* out) const {
00119 for (int r=0; r<rows; r++) {
00120 for (int c=0; c<cols; c++)
00121 fprintf (out, "%g ", get(r,c));
00122 fprintf (out, "\n");
00123 }
00124 }
00125
00126
00127
00128
00129 const Matrix& Matrix::transpose () {
00130 for (int i=0; i<rows; i++)
00131 for (int j=i; j<cols; j++)
00132 swap (get(i,j), get(j,i));
00133 return *this;
00134 }
00135
00138 const Matrix& Matrix::multiplyToSum (double s) {
00139 double cs = sum ();
00140 ASSERTWITH (fabs(cs)>1E-10, "Tried to normalize a zero matrix");
00141
00142 operator*= (1.0/cs);
00143 return *this;
00144 }
00145
00146
00147
00148
00149 double Matrix::sum () const
00150 {
00151 int size=rows*cols;
00152 double res=0.0;
00153 for (int i=0; i<size; i++)
00154 res += mData[i];
00155 return res;
00156 }
00157
00160 double Matrix::det () const
00161 {
00162 if (rows != cols || rows<2)
00163 return 0;
00164
00165 if (rows == 2)
00166 return mData[0]*mData[3] - mData[1]*mData[2];
00167
00168
00169
00170
00171 int rownon0;
00172 for (rownon0=0; rownon0<rows; rownon0++)
00173 if (get(rownon0,0) != 0)
00174 break;
00175
00176 if (rownon0 == rows)
00177 return 0;
00178
00179
00180
00181 Matrix modified (*this);
00182 double scale_to = get(rownon0, 0);
00183 for (int row=0; row<rows; row++)
00184 if (row != rownon0 && get(row,0)!=0)
00185 modified.addRowByScalar (rownon0, row, -get(row,0)/scale_to);
00186
00187
00188 Matrix cmpl = modified.complement (rownon0, 0);
00189
00190
00191
00192 return get(rownon0, 0) * cmpl.det () * (1-(rownon0%2)*2);
00193 }
00194
00197 Matrix Matrix::complement (int row, int col) const
00198 {
00199 ASSERT (rows>1 && rows==cols);
00200
00201 Matrix result (rows-1, cols-1);
00202
00203 for (int i=0, trgrow=0; i<rows; i++)
00204 if (i != row) {
00205 for (int j=0, trgcol=0; j<cols; j++)
00206 if (j!=col)
00207 result.get(trgrow, trgcol++) = get (i,j);
00208 trgrow++;
00209 }
00210
00211 return result;
00212 }
00213
00216 void Matrix::mulRowByScalar (int row, double scalar)
00217 {
00218 for (int i=0; i<cols; i++)
00219 get(row,i) *= scalar;
00220 }
00221
00226 void Matrix::addRowByScalar (int srcrow, int dstrow, double scalar)
00227 {
00228 for (int i=0; i<cols; i++) {
00229 get(dstrow,i) += scalar*get(srcrow,i);
00230
00231
00232 if (isRoundZero (get(dstrow,i)))
00233 get(dstrow,i) = 0;
00234 }
00235 }
00236
00239 void Matrix::swaprows (int row1, int row2)
00240 {
00241 double tmp [cols];
00242 int collen = cols * sizeof(double);
00243 memcpy (&tmp, mData + row1*cols, collen);
00244 memcpy (mData + row1*cols, mData + row2*cols, collen);
00245 memcpy (mData + row2*cols, &tmp, collen);
00246 }
00247
00250 const Matrix& Matrix::operator= (double x) {
00251 int size=rows*cols;
00252 for (int i=0; i<size; i++)
00253 mData[i] = x;
00254 return *this;
00255 }
00256
00259 const Matrix& Matrix::operator= (const Matrix& orig) {
00260 make (orig.rows, orig.cols);
00261 int size=rows*cols;
00262 for (int i=0; i<size; i++)
00263 mData[i]= orig.mData[i];
00264 return *this;
00265 }
00266
00269 const Matrix& Matrix::operator+= (const Matrix& other) {
00270 int size=rows*cols;
00271 for (int i=0; i<size; i++)
00272 mData[i] += other.mData[i];
00273 return *this;
00274 }
00275
00278 const Matrix& Matrix::operator+= (double x) {
00279 int size=rows*cols;
00280 for (int i=0; i<size; i++)
00281 mData[i] += x;
00282 return *this;
00283 }
00284
00287 const Matrix& Matrix::operator*= (const Matrix& other) {
00288 int size=rows*cols;
00289 for (int i=0; i<size; i++)
00290 mData[i] *= other.mData[i];
00291 return *this;
00292 }
00293
00296 const Matrix& Matrix::operator*= (double x) {
00297 int size=rows*cols;
00298 for (int i=0; i<size; i++)
00299 mData[i] *= x;
00300 return *this;
00301 }
00302
00303
00304
00305
00306 TextOStream& Matrix::operator>> (TextOStream& out) const
00307 {
00308 out << "{";
00309 for (int i=0; i<rows; i++) {
00310 if (i > 0)
00311 out << ' ';
00312 out << '{';
00313 for (int j=0; j < cols; j++) {
00314 out.printf ("%2f", get (i,j));
00315 if (j < cols-1)
00316 out << ',';
00317 }
00318 out << '}';
00319 if (i < rows-1)
00320 out << '\n';
00321 }
00322 out << "}\n";
00323 return out;
00324 }
00325
00328 void Matrix::splitVertical (Matrix& a, Matrix& b, int column) const {
00329 a.make (rows, column);
00330 b.make (rows, cols-column);
00331 for (int r=0; r<rows; r++) {
00332 for (int c=0; c<column; c++)
00333 a.get(r,c) = get(r,c);
00334 for (int c=0; c<cols-column; c++)
00335 b.get(r,c) = get(r,c+column);
00336 }
00337 }
00338
00341 void Matrix::splitHorizontal (Matrix& a, Matrix& b, int row) const {
00342 a.make (row, cols);
00343 b.make (rows-row, cols);
00344 for (int c=0; c<cols; c++) {
00345 for (int r=0; r<row; r++)
00346 a.get(r,c) = get(r,c);
00347 for (int r=0; r<rows-row; r++)
00348 b.get(r,c) = get(r+row,c);
00349 }
00350 }
00351
00356 void Matrix::joinVertical (const Matrix& a, const Vector& b)
00357 {
00358 ASSERT (a.rows == b.size ());
00359
00360 make (a.rows, a.cols+1);
00361
00362 int collen = cols*sizeof(double);
00363 int acollen = a.cols*sizeof(double);
00364 for (int r=0; r<rows; r++) {
00365
00366 memcpy (mData + r*collen, a.mData + r*acollen, acollen);
00367
00368
00369 mData[r*cols + cols-1] = b[r];
00370 }
00371 }
00372
00377 void Matrix::joinVertical (const Matrix& a, const Matrix& b) {
00378 ASSERT (a.rows == b.rows);
00379 make (a.rows, a.cols + b.cols);
00380 for (int r=0; r<rows; r++) {
00381 for (int c=0; c<a.cols; c++)
00382 get(r,c) = a.get(r,c);
00383 for (int c=0; c<b.cols; c++)
00384 get(r,c+a.cols) = a.get(r,c);
00385 }
00386 }
00387
00392 void Matrix::joinHorizontal (const Matrix& a, const Matrix& b) {
00393 ASSERT (a.cols == b.cols);
00394 make (a.rows+b.rows, a.cols);
00395 for (int c=0; c<cols; c++) {
00396 for (int r=0; r<a.rows; r++)
00397 get(r,c) = a.get(r,c);
00398 for (int r=0; r<b.rows; r++)
00399 get(r+a.rows,c) = a.get(r,c);
00400 }
00401 }
00402
00405 Matrix Matrix::sub (int row0, int row1, int col0, int col1) const {
00406 ASSERT (row0>=0 && row0<rows);
00407 ASSERT ((row1>=-1 && row1<rows) || row1==-1);
00408 ASSERT (col0>=0 && col0<cols);
00409 ASSERT ((col1>=-1 && col1<cols) || col1==-1);
00410
00411 if (row1==-1)
00412 row1 = rows-1;
00413 if (col1==-1)
00414 col1 = cols-1;
00415
00416 Matrix result;
00417 result.make (row1-row0+1, col1-col0+1);
00418 for (int r=0; r<result.rows; r++)
00419 for (int c=0; c<result.cols; c++)
00420 result.get(r,c) = (*this).get(r+row0, c+col0);
00421 return result;
00422 }
00423
00424
00425
00426
00427 void Matrix::insertColumn (int cols) {
00428
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00453 int solveLinear (const Matrix& mat, const Vector& b, Vector& result)
00454 {
00455
00456 Matrix augmat (mat);
00457 augmat.joinVertical (mat, b);
00458
00459 return solveLinear (augmat, result);
00460 }
00461
00473 int solveLinear (const Matrix& augmat_orig, Vector& result, int* bv_set)
00474 {
00475 int bv_count = 0;
00476
00477
00478
00479 Matrix augmat (augmat_orig);
00480
00481
00482 for (int col=0, row=0; col<augmat.cols-1 && row<augmat.rows; col++)
00483
00484 if (!bv_set || bv_set[col]) {
00485
00486
00487 if (augmat.get(row,col) == 0) {
00488
00489 bool found = false;
00490 for (int i=row+1; i<augmat.rows; i++)
00491 if (augmat.get(i,col) != 0) {
00492 augmat.swaprows (row, i);
00493 found = true;
00494 }
00495
00496 if (!found)
00497 return 1;
00498 }
00499
00500
00501 augmat.mulRowByScalar (row, 1/augmat.get(row,col));
00502 augmat.get(row,col) = 1;
00503
00504
00505 for (int i=row+1; i<augmat.rows; i++)
00506 if (augmat.get(i,col) != 0) {
00507 augmat.addRowByScalar (row, i, -augmat.get(i,col));
00508 augmat.get(i,col) = 0;
00509 }
00510
00511 row++;
00512 }
00513 else
00514
00515 bv_count++;
00516
00517
00518 if (augmat.rows > augmat.cols - bv_count - 1)
00519 for (int i=augmat.cols - bv_count - 1; i<augmat.rows; i++)
00520 if (!bv_set || bv_set[i])
00521 if (!isRoundZero (augmat.get(i,augmat.cols - bv_count - 1)))
00522 return 2;
00523
00524
00525 for (int col=augmat.cols-2, row=augmat.rows-1; col>=0; col--)
00526 if (!bv_set || bv_set[col]) {
00527
00528 for (int i=row-1; i>=0; i--)
00529 if (augmat.get(i,col) != 0)
00530 augmat.addRowByScalar (row, i, -augmat.get(i,col));
00531
00532 row--;
00533 }
00534
00535
00536 result.make (augmat.cols-1);
00537 for (int var=0, row=0; var<result.size(); var++)
00538 if (!bv_set || bv_set[var])
00539 result[var] = augmat.get (row++, augmat.cols-1);
00540 else
00541 result[var] = 0.0;
00542
00543 return 0;
00544 }
00545
00546 END_NAMESPACE;
00547