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