00001 /*
00002 File: Mat.cc
00003
00004 Function: Implements Mat.h
00005
00006 Author(s): Andrew Willmott
00007
00008 Copyright: (c) 1995-2000, Andrew Willmott
00009
00010 Notes:
00011
00012 */
00013
00014 #include "vl/Mat.h"
00015 #include <ctype.h>
00016 #include <string.h>
00017 #include <stdarg.h>
00018 #include <iomanip.h>
00019 #ifndef __SVL__
00020 #include "cl/Array.h"
00021 #endif
00022
00023
00024 // --- Mat Constructors & Destructors -----------------------------------------
00025
00026
00027 TMat::TMat(Int rows, Int cols, ZeroOrOne k) : rows(rows), cols(cols)
00028 {
00029 Assert(rows > 0 && cols > 0, "(Mat) illegal matrix size");
00030
00031 data = new TMReal[rows * cols];
00032 Assert(data != 0, "(Mat) Out of memory");
00033
00034 MakeDiag(k);
00035 }
00036
00037 TMat::TMat(Int rows, Int cols, Block k) : rows(rows), cols(cols)
00038 {
00039 Assert(rows > 0 && cols > 0, "(Mat) illegal matrix size");
00040
00041 data = new TMReal[rows * cols];
00042 Assert(data != 0, "(Mat) Out of memory");
00043
00044 MakeBlock(k);
00045 }
00046
00047 TMat::TMat(Int rows, Int cols, double elt0, ...) : rows(rows), cols(cols)
00048 // The double is hardwired here because it is the only type that will work
00049 // with var args and C++ real numbers.
00050 {
00051 Assert(rows > 0 && cols > 0, "(Mat) illegal matrix size");
00052
00053 va_list ap;
00054 Int i, j;
00055
00056 data = new TMReal[rows * cols];
00057 Assert(data != 0, "(Mat) Out of memory");
00058 va_start(ap, elt0);
00059
00060 SetReal(data[0], elt0);
00061
00062 for (i = 1; i < cols; i++)
00063 SetReal(SELF[0][i], va_arg(ap, double));
00064
00065 for (i = 1; i < rows; i++)
00066 for (j = 0; j < cols; j++)
00067 SetReal(SELF[i][j], va_arg(ap, double));
00068
00069 va_end(ap);
00070 }
00071
00072 TMat::TMat(const TMat &m) : cols(m.cols)
00073 {
00074 Assert(m.data != 0, "(Mat) Can't construct from null matrix");
00075 rows = m.Rows();
00076
00077 UInt elts = rows * cols;
00078
00079 data = new TMReal[elts];
00080 Assert(data != 0, "(Mat) Out of memory");
00081 memcpy(data, m.data, elts * sizeof(TMReal));
00082 }
00083
00084 #ifndef __SVL__
00085 TMat::TMat(const TSubMat &m) : rows(m.Rows()), cols(m.Cols())
00086 {
00087 data = new TMReal[rows * cols];
00088 Assert(data != 0, "(Mat) Out of memory");
00089
00090 for (Int i = 0; i < Rows(); i++)
00091 SELF[i] = m[i];
00092 }
00093 #endif
00094
00095 TMat::TMat(const TMat2 &m) : rows(2 | VL_REF_FLAG), cols(2), data(m.Ref())
00096 {
00097 }
00098
00099 TMat::TMat(const TMat3 &m) : rows(3 | VL_REF_FLAG), cols(3), data(m.Ref())
00100 {
00101 }
00102
00103 TMat::TMat(const TMat4 &m) : rows(4 | VL_REF_FLAG), cols(4), data(m.Ref())
00104 {
00105 }
00106
00107
00108 // --- Mat Assignment Operators -----------------------------------------------
00109
00110
00111 TMat &TMat::operator = (const TMat &m)
00112 {
00113 if (!IsRef())
00114 SetSize(m.Rows(), m.Cols());
00115 else
00116 Assert(Rows() == m.Rows(), "(Mat::=) Matrix rows don't match");
00117 for (Int i = 0; i < Rows(); i++)
00118 SELF[i] = m[i];
00119
00120 return(SELF);
00121 }
00122
00123 #ifndef __SVL__
00124 TMat &TMat::operator = (const TSubMat &m)
00125 {
00126 if (!IsRef())
00127 SetSize(m.Rows(), m.Cols());
00128 else
00129 Assert(Rows() == m.Rows(), "(Mat::=) Matrix rows don't match");
00130 for (Int i = 0; i < Rows(); i++)
00131 SELF[i] = m[i];
00132
00133 return(SELF);
00134 }
00135 #endif
00136
00137 TMat &TMat::operator = (const TMat2 &m)
00138 {
00139 if (!IsRef())
00140 SetSize(m.Rows(), m.Cols());
00141 else
00142 Assert(Rows() == m.Rows(), "(Mat::=) Matrix rows don't match");
00143 for (Int i = 0; i < Rows(); i++)
00144 SELF[i] = m[i];
00145
00146 return(SELF);
00147 }
00148
00149 TMat &TMat::operator = (const TMat3 &m)
00150 {
00151 if (!IsRef())
00152 SetSize(m.Rows(), m.Cols());
00153 else
00154 Assert(Rows() == m.Rows(), "(Mat::=) Matrix rows don't match");
00155 for (Int i = 0; i < Rows(); i++)
00156 SELF[i] = m[i];
00157
00158 return(SELF);
00159 }
00160
00161 TMat &TMat::operator = (const TMat4 &m)
00162 {
00163 if (!IsRef())
00164 SetSize(m.Rows(), m.Cols());
00165 else
00166 Assert(Rows() == m.Rows(), "(Mat::=) Matrix rows don't match");
00167
00168 for (Int i = 0; i < Rows(); i++)
00169 SELF[i] = m[i];
00170
00171 return(SELF);
00172 }
00173
00174 Void TMat::SetSize(Int nrows, Int ncols)
00175 {
00176 UInt elts = nrows * ncols;
00177 Assert(elts > 0, "(Mat::SetSize) Illegal matrix size.");
00178 UInt oldElts = Rows() * Cols();
00179 Bool wasRef = IsRef();
00180
00181 rows = nrows;
00182 cols = ncols;
00183
00184 if (wasRef)
00185 {
00186 // Do we already have enough storage?
00187 rows |= VL_REF_FLAG;
00188 if (elts <= oldElts)
00189 return;
00190
00191 _Error("(Mat::SetSize) Trying to increase size of a reference vector");
00192
00193 delete[] data;
00194 }
00195
00196 data = new TMReal[elts];
00197 Assert(data != 0, "(Mat::SetSize) Out of memory");
00198 }
00199
00200 Void TMat::SetSize(const TMat &m)
00201 {
00202 SetSize(m.Rows(), m.Cols());
00203 }
00204
00205 Void TMat::MakeZero()
00206 {
00207 Int i, j;
00208
00209 for (i = 0; i < Rows(); i++)
00210 for (j = 0; j < Cols(); j++)
00211 Elt(i,j) = vl_zero;
00212 }
00213
00214 Void TMat::MakeDiag(TMReal k)
00215 {
00216 Int i, j;
00217
00218 for (i = 0; i < Rows(); i++)
00219 for (j = 0; j < Cols(); j++)
00220 if (i == j)
00221 Elt(i,j) = k;
00222 else
00223 Elt(i,j) = vl_zero;
00224 }
00225
00226 Void TMat::MakeDiag()
00227 {
00228 Int i, j;
00229
00230 for (i = 0; i < Rows(); i++)
00231 for (j = 0; j < Cols(); j++)
00232 Elt(i,j) = (i == j) ? vl_one : vl_zero;
00233 }
00234
00235 Void TMat::MakeBlock(TMReal k)
00236 {
00237 Int i, j;
00238
00239 for (i = 0; i < Rows(); i++)
00240 for (j = 0; j < Cols(); j++)
00241 Elt(i,j) = k;
00242 }
00243
00244 Void TMat::MakeBlock()
00245 {
00246 Int i, j;
00247
00248 for (i = 0; i < Rows(); i++)
00249 for (j = 0; j < Cols(); j++)
00250 Elt(i,j) = vl_one;
00251 }
00252
00253
00254 // --- Mat Assignment Operators -----------------------------------------------
00255
00256
00257 TMat &operator += (TMat &m, const TMat &n)
00258 {
00259 Assert(n.Rows() == m.Rows(), "(Mat::+=) matrix rows don't match");
00260
00261 Int i;
00262 TMVec t;
00263
00264 for (i = 0; i < n.Rows(); i++)
00265 m[i] += n[i];
00266
00267 return(m);
00268 }
00269
00270 TMat &operator -= (TMat &m, const TMat &n)
00271 {
00272 Assert(n.Rows() == m.Rows(), "(Mat::-=) matrix rows don't match");
00273
00274 Int i;
00275 TMVec t;
00276
00277 for (i = 0; i < m.Rows(); i++)
00278 m[i] -= n[i];
00279
00280 return(m);
00281 }
00282
00283 TMat &operator *= (TMat &m, const TMat &n)
00284 {
00285 Assert(m.Cols() == n.Cols(), "(Mat::*=) matrix columns don't match");
00286
00287 Int i;
00288 TMVec t;
00289
00290 for (i = 0; i < m.Rows(); i++)
00291 m[i] *= n;
00292
00293 return(m);
00294 }
00295
00296 TMat &operator *= (TMat &m, TMReal s)
00297 {
00298 Int i;
00299 TMVec t;
00300
00301 for (i = 0; i < m.Rows(); i++)
00302 m[i] *= s;
00303
00304 return(m);
00305 }
00306
00307 TMat &operator /= (TMat &m, TMReal s)
00308 {
00309 Int i;
00310 TMVec t;
00311
00312 for (i = 0; i < m.Rows(); i++)
00313 m[i] /= s;
00314
00315 return(m);
00316 }
00317
00318
00319 // --- Mat Comparison Operators -----------------------------------------------
00320
00321
00322 Bool operator == (const TMat &m, const TMat &n)
00323 {
00324 Assert(n.Rows() == m.Rows(), "(Mat::==) matrix rows don't match");
00325
00326 Int i;
00327
00328 for (i = 0; i < m.Rows(); i++)
00329 if (m[i] != n[i])
00330 return(0);
00331
00332 return(1);
00333 }
00334
00335 Bool operator != (const TMat &m, const TMat &n)
00336 {
00337 Assert(n.Rows() == m.Rows(), "(Mat::!=) matrix rows don't match");
00338
00339 Int i;
00340
00341 for (i = 0; i < m.Rows(); i++)
00342 if (m[i] != n[i])
00343 return(1);
00344
00345 return(0);
00346 }
00347
00348
00349 // --- Mat Arithmetic Operators -----------------------------------------------
00350
00351
00352 TMat operator + (const TMat &m, const TMat &n)
00353 {
00354 Assert(n.Rows() == m.Rows(), "(Mat::+) matrix rows don't match");
00355
00356 TMat result(m.Rows(), m.Cols());
00357 Int i;
00358
00359 for (i = 0; i < m.Rows(); i++)
00360 result[i] = m[i] + n[i];
00361
00362 return(result);
00363 }
00364
00365 TMat operator - (const TMat &m, const TMat &n)
00366 {
00367 Assert(n.Rows() == m.Rows(), "(Mat::-) matrix rows don't match");
00368
00369 TMat result(m.Rows(), m.Cols());
00370 Int i;
00371
00372 for (i = 0; i < m.Rows(); i++)
00373 result[i] = m[i] - n[i];
00374
00375 return(result);
00376 }
00377
00378 TMat operator - (const TMat &m)
00379 {
00380 TMat result(m.Rows(), m.Cols());
00381 Int i;
00382
00383 for (i = 0; i < m.Rows(); i++)
00384 result[i] = -m[i];
00385
00386 return(result);
00387 }
00388
00389 TMat operator * (const TMat &m, const TMat &n)
00390 {
00391 Assert(m.Cols() == n.Rows(), "(Mat::*m) matrix cols don't match");
00392
00393 TMat result(m.Rows(), n.Cols());
00394 Int i;
00395
00396 for (i = 0; i < m.Rows(); i++)
00397 result[i] = m[i] * n;
00398
00399 return(result);
00400 }
00401
00402 TMVec operator * (const TMat &m, const TMVec &v)
00403 {
00404 Assert(m.Cols() == v.Elts(), "(Mat::*v) matrix and vector sizes don't match");
00405
00406 Int i;
00407 TMVec result(m.Rows());
00408
00409 for (i = 0; i < m.Rows(); i++)
00410 result[i] = dot(v, m[i]);
00411
00412 return(result);
00413 }
00414
00415 TMat operator * (const TMat &m, TMReal s)
00416 {
00417 Int i;
00418 TMat result(m.Rows(), m.Cols());
00419
00420 for (i = 0; i < m.Rows(); i++)
00421 result[i] = m[i] * s;
00422
00423 return(result);
00424 }
00425
00426 TMat operator / (const TMat &m, TMReal s)
00427 {
00428 Int i;
00429 TMat result(m.Rows(), m.Cols());
00430
00431 for (i = 0; i < m.Rows(); i++)
00432 result[i] = m[i] / s;
00433
00434 return(result);
00435 }
00436
00437
00438 // --- Mat Mat-Vec Functions --------------------------------------------------
00439
00440
00441 TMVec operator * (const TMVec &v, const TMat &m) // v * m
00442 {
00443 Assert(v.Elts() == m.Rows(), "(Mat::v*m) vector/matrix sizes don't match");
00444
00445 TMVec result(m.Cols(), vl_zero);
00446 Int i;
00447
00448 for (i = 0; i < m.Rows(); i++)
00449 result += m[i] * v[i];
00450
00451 return(result);
00452 }
00453
00454 TMVec &operator *= (TMVec &v, const TMat &m) // v *= m
00455 {
00456 v = v * m; // Can't optimise much here...
00457
00458 return(v);
00459 }
00460
00461
00462 // --- Mat Special Functions --------------------------------------------------
00463
00464
00465 TMat trans(const TMat &m)
00466 {
00467 Int i,j;
00468 TMat result(m.Cols(), m.Rows());
00469
00470 for (i = 0; i < m.Rows(); i++)
00471 for (j = 0; j < m.Cols(); j++)
00472 result.Elt(j,i) = m.Elt(i,j);
00473
00474 return(result);
00475 }
00476
00477 TMReal trace(const TMat &m)
00478 {
00479 Int i;
00480 TMReal result = vl_0;
00481
00482 for (i = 0; i < m.Rows(); i++)
00483 result += m.Elt(i,i);
00484
00485 return(result);
00486 }
00487
00488 TMat &TMat::Clamp(Real fuzz)
00489 // clamps all values of the matrix with a magnitude
00490 // smaller than fuzz to zero.
00491 {
00492 Int i;
00493
00494 for (i = 0; i < Rows(); i++)
00495 SELF[i].Clamp(fuzz);
00496
00497 return(SELF);
00498 }
00499
00500 TMat &TMat::Clamp()
00501 {
00502 return(Clamp(1e-7));
00503 }
00504
00505 TMat clamped(const TMat &m, Real fuzz)
00506 // clamps all values of the matrix with a magnitude
00507 // smaller than fuzz to zero.
00508 {
00509 TMat result(m);
00510
00511 return(result.Clamp(fuzz));
00512 }
00513
00514 TMat clamped(const TMat &m)
00515 {
00516 return(clamped(m, 1e-7));
00517 }
00518
00519 TMat oprod(const TMVec &a, const TMVec &b)
00520 // returns outerproduct of a and b: a * trans(b)
00521 {
00522 TMat result;
00523 Int i;
00524
00525 result.SetSize(a.Elts(), b.Elts());
00526 for (i = 0; i < a.Elts(); i++)
00527 result[i] = a[i] * b;
00528
00529 return(result);
00530 }
00531
00532
00533 // --- Mat Input & Output -----------------------------------------------------
00534
00535
00536 ostream &operator << (ostream &s, const TMat &m)
00537 {
00538 Int i, w = s.width();
00539
00540 s << '[';
00541 for (i = 0; i < m.Rows() - 1; i++)
00542 s << setw(w) << m[i] << endl;
00543 s << setw(w) << m[i] << ']' << endl;
00544 return(s);
00545 }
00546
00547 #ifndef __SVL__
00548 istream &operator >> (istream &s, TMat &m)
00549 {
00550 Array< Array<TMReal> > array;
00551 Int i;
00552
00553 s >> array; // Read input into array of arrays
00554
00555 m.SetSize(array.NumItems(), array[0].NumItems());
00556
00557 for (i = 0; i < m.Rows(); i++) // copy the result into m
00558 {
00559 Assert(m.Cols() == array[i].NumItems(), "(Mat/>>) different sized matrix rows");
00560 m[i] = TMVec(m.Cols(), array[i].Ref());
00561 }
00562
00563 return(s);
00564 }
00565 #endif
00566
00567 //
00568 // inv: matrix inversion using Gaussian pivoting
00569 //
00570
00571 #if !defined(CL_CHECKING) && !defined(VL_CHECKING)
00572 // we #define away pAssertEps if it is not used, to avoid
00573 // compiler warnings.
00574 #define pAssertEps
00575 #endif
00576
00577 TMat inv(const TMat &m, TMReal *determinant, TMReal pAssertEps)
00578 {
00579 Assert(m.IsSquare(), "(inv) Matrix not square");
00580
00581 Int i, j, k;
00582 Int n = m.Rows();
00583 TMReal t, pivot, det;
00584 Real max;
00585 TMat A(m);
00586 TMat B(n, n, vl_I);
00587
00588 // ---------- Forward elimination ---------- ------------------------------
00589
00590 det = vl_1;
00591
00592 for (i = 0; i < n; i++) // Eliminate in column i, below diag
00593 {
00594 max = -1.0;
00595
00596 for (k = i; k < n; k++) // Find a pivot for column i
00597 if (len(A[k][i]) > max)
00598 {
00599 max = len(A[k][i]);
00600 j = k;
00601 }
00602
00603 Assert(max > pAssertEps, "(inv) Matrix not invertible");
00604
00605 if (j != i) // Swap rows i and j
00606 {
00607 for (k = i; k < n; k++)
00608 Swap(A.Elt(i, k), A.Elt(j, k));
00609 for (k = 0; k < n; k++)
00610 Swap(B.Elt(i, k), B.Elt(j, k));
00611
00612 det = -det;
00613 }
00614
00615 pivot = A.Elt(i, i);
00616 Assert(abs(pivot) > pAssertEps, "(inv) Matrix not invertible");
00617 det *= pivot;
00618
00619 for (k = i + 1; k < n; k++) // Only do elements to the right of the pivot
00620 A.Elt(i, k) /= pivot;
00621
00622 for (k = 0; k < n; k++)
00623 B.Elt(i, k) /= pivot;
00624
00625 // We know that A(i, i) will be set to 1, so don't bother to do it
00626
00627 for (j = i + 1; j < n; j++)
00628 { // Eliminate in rows below i
00629 t = A.Elt(j, i); // We're gonna zero this guy
00630 for (k = i + 1; k < n; k++) // Subtract scaled row i from row j
00631 A.Elt(j, k) -= A.Elt(i, k) * t; // (Ignore k <= i, we know they're 0)
00632 for (k = 0; k < n; k++)
00633 B.Elt(j, k) -= B.Elt(i, k) * t;
00634 }
00635 }
00636
00637 // ---------- Backward elimination ---------- -----------------------------
00638
00639 for (i = n - 1; i > 0; i--) // Eliminate in column i, above diag
00640 {
00641 for (j = 0; j < i; j++) // Eliminate in rows above i
00642 {
00643 t = A.Elt(j, i); // We're gonna zero this guy
00644 for (k = 0; k < n; k++) // Subtract scaled row i from row j
00645 B.Elt(j, k) -= B.Elt(i, k) * t;
00646 }
00647 }
00648 if (determinant)
00649 *determinant = det;
00650 return(B);
00651 }
00652