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