20 #ifndef MIRTK_SparseMatrix_H 21 #define MIRTK_SparseMatrix_H 23 #include "mirtk/Config.h" 24 #include "mirtk/Object.h" 26 #include "mirtk/Assert.h" 27 #include "mirtk/Memory.h" 28 #include "mirtk/Vector.h" 29 #include "mirtk/Matrix.h" 30 #include "mirtk/Math.h" 31 #include "mirtk/Pair.h" 32 #include "mirtk/Array.h" 33 #include "mirtk/Algorithm.h" 34 #include "mirtk/Profiling.h" 36 #include "mirtk/NumericsConfig.h" 37 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 38 # include "mirtk/Matlab.h" 50 template <
class TEntry>
67 typedef Pair<int, TEntry>
Entry;
111 template <
class TOtherEntry>
131 template <
class TOtherEntry>
135 template <
class TOtherEntry>
142 void Initialize(
int,
int, Array<Entries> &,
bool =
false);
145 void Initialize(
int,
int, Entries [],
bool =
false);
147 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 169 int GetRawData(
int *&,
int *&, TEntry *&)
const;
190 int SubNNZ(
int,
int,
int,
int)
const;
219 void Put(
int,
int, EntryType);
222 EntryType
Get(
int,
int = -1)
const;
226 void GetRow(
int, Entries &)
const;
234 void Row(
int, Entries &,
bool =
false);
238 Entries
Row(
int)
const;
242 void GetCol(
int, Entries &)
const;
250 void Col(
int, Entries &,
bool =
false);
254 Entries
Col(
int)
const;
263 void Column(
int, Entries &,
bool =
false);
267 Entries
Column(
int)
const;
288 virtual void Clear();
301 void Transpose(
bool keep_layout =
false);
305 EntryType
RowSum(
int)
const;
309 EntryType
ColSum(
int)
const;
317 void MultAv(EntryType [], EntryType [])
const;
381 int p = 0,
double tol = .0,
int maxit = 0,
Vector *v0 = NULL)
const;
406 int p = 0,
double tol = .0,
int maxit = 0,
Vector *v0 = NULL)
const;
431 int p = 0,
double tol = .0,
int maxit = 0,
Vector *v0 = NULL)
const;
435 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 445 mxArray *MxArray()
const;
454 bool ReadMAT(
const char *,
const char * =
"A");
461 bool WriteMAT(
const char *,
const char * =
"A")
const;
466 void WriteMFile(
const char *,
const char * =
"A")
const;
478 template <
class TEntry>
481 const int n = (_Layout == CRS ? _Cols : _Rows);
483 for (
typename Entries::iterator i = entries.begin(); i != entries.end(); ++i) {
484 if (i->second == TEntry(0)) {
485 typename Entries::iterator j = i; --i;
487 }
else if (i->first < 0 || i->first >= n) {
488 cerr <<
"GenericSparseMatrix::CheckEntries: Invalid " 489 << (_Layout == CRS ?
"column" :
"row") <<
" index: " 495 sort(entries.begin(), entries.end());
497 for (
typename Entries::iterator i = entries.begin(); i != entries.end(); ++i) {
498 typename Entries::iterator j = i + 1;
499 while (j != entries.end() && i->first == j->first) {
500 i->second += j->second, ++j;
502 entries.erase(i + 1, i + std::distance(i, j));
511 template <
class TEntry>
template <
class TOtherEntry>
521 _Layout = other._Layout;
526 _MaxNumberOfUnusedEntries = other._MaxNumberOfUnusedEntries;
528 if (_Layout == CRS) {
529 _Row = Allocate<int> (_Rows + 1);
530 _Col = Allocate<int> (_Size);
531 _Data = Allocate<TEntry>(_Size);
532 for (
int r = 0; r <= _Rows; ++r)
_Row[r] = other.
_Row[r];
533 for (
int i = 0; i <= _NNZ; ++i) {
534 _Col [i] = other.
_Col [i];
535 _Data[i] = other.
_Data[i];
538 _Row = Allocate<int> (_Size);
539 _Col = Allocate<int> (_Cols + 1);
540 _Data = Allocate<TEntry>(_Size);
541 for (
int c = 0; c <= _Cols; ++c) _Col[c] = other.
_Col[c];
542 for (
int i = 0; i <= _NNZ; ++i) {
544 _Data[i] = other.
_Data[i];
550 template <
class TEntry>
558 _MaxNumberOfUnusedEntries(100),
567 template <
class TEntry>
576 _MaxNumberOfUnusedEntries(100),
582 if (_Layout == CRS) _Row = CAllocate<int>(_Rows + 1);
583 else _Col = CAllocate<int>(_Cols + 1);
587 template <
class TEntry>
596 _MaxNumberOfUnusedEntries(100),
602 if (_Layout == CRS) {
603 _Row = CAllocate<int>(_Rows + 1);
604 _Col = Allocate<int>(nnz);
606 _Row = Allocate<int>(nnz);
607 _Col = CAllocate<int>(_Cols + 1);
609 _Data = Allocate<TEntry>(nnz);
613 template <
class TEntry>
template <
class TOtherEntry>
617 _Row(NULL), _Col(NULL), _Data(NULL), _Index(NULL)
619 CopyAttributes(other);
623 template <
class TEntry>
template <
class TOtherEntry>
627 if (
this != &other) {
628 Object::operator =(other);
629 CopyAttributes(other);
635 template <
class TEntry>
647 if (_Rows > 0 && _Cols > 0) {
648 if (_Layout == CRS) _Row = CAllocate<int>(_Rows + 1);
649 else _Col = CAllocate<int>(_Cols + 1);
654 if (_Layout == CRS) _Col = Allocate<int>(sz);
655 else _Row = Allocate<int>(sz);
656 _Data = Allocate<TEntry>(sz);
662 template <
class TEntry>
672 _Rows = m, _Cols = n;
673 if (_Layout == CCS) swap(m, n);
676 for (
int r = 0; r < m; ++r) CheckEntries(entries[r]);
679 for (
int r = 0; r < m; ++r) {
680 _NNZ +=
static_cast<int>(entries[r].size());
683 _Row = Allocate<int>(m + 1);
684 _Col = Allocate<int>(_NNZ);
685 _Data = Allocate<EntryType>(_NNZ);
689 for (
int r = 0; r < m; ++r) {
691 typename Entries::const_iterator entry;
692 for (entry = entries[r].begin(); entry != entries[r].end(); ++entry, ++i) {
693 _Col [i] = entry->first;
694 _Data[i] = entry->second;
699 if (_Layout == CCS) swap(_Row, _Col);
703 template <
class TEntry>
713 _Rows = m, _Cols = n;
714 if (_Layout == CCS) swap(m, n);
716 for (
int r = 0; r < m; ++r) CheckEntries(entries[r]);
719 for (
int r = 0; r < m; ++r) {
720 _NNZ +=
static_cast<int>(entries[r].size());
723 _Row = Allocate<int>(m + 1);
724 _Col = Allocate<int>(_NNZ);
725 _Data = Allocate<EntryType>(_NNZ);
729 for (
int r = 0; r < m; ++r) {
731 typename Entries::const_iterator entry;
732 for (entry = entries[r].begin(); entry != entries[r].end(); ++entry, ++i) {
733 _Col [i] = entry->first;
734 _Data[i] = entry->second;
739 if (_Layout == CCS) swap(_Row, _Col);
743 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 744 template <
class TEntry>
753 _Rows =
static_cast<int>(mxGetM(pm));
754 _Cols =
static_cast<int>(mxGetN(pm));
756 if (mxIsSparse(pm)) {
759 const mwIndex *ir = mxGetIr(pm);
760 const mwIndex *jc = mxGetJc(pm);
761 const double *pr = mxGetPr(pm);
764 _Size = _NNZ = jc[_Cols];
765 _Col = Allocate<int>(_Cols + 1);
766 _Row = Allocate<int>(_Size);
767 _Data = Allocate<EntryType>(_Size);
769 for (
int c = 0; c <= _Cols; ++c) {
772 for (
int i = 0; i < _NNZ; ++i) {
779 cerr <<
"GenericSparseMatrix::Initialize: Initialization from non-sparse mxArray not implemented" << endl;
783 #endif // MIRTK_Numerics_WITH_MATLAB 786 template <
class TEntry>
800 template <
class TEntry>
803 if (layout != CRS && layout != CCS) {
804 cerr <<
"GenericSparseMatrix::Layout: Unknown storage layout: " << layout << endl;
807 if (layout != _Layout) {
808 if (_NNZ == 0) swap(_Row, _Col);
809 else Transpose(
true);
815 template <
class TEntry>
825 template <
class TEntry>
832 template <
class TEntry>
839 template <
class TEntry>
842 if (sz < _NNZ) sz = _NNZ;
843 int *&old_idx = (_Layout == CRS ? _Col : _Row);
844 int *new_idx = Allocate<int> (sz);
845 TEntry *new_data = Allocate<TEntry>(sz);
846 memcpy(new_idx, old_idx, _NNZ *
sizeof(
int));
847 memcpy(new_data, _Data, _NNZ *
sizeof(TEntry));
856 template <
class TEntry>
860 int rows, *col, *row;
861 if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
862 else rows = _Rows, row = _Row, col = _Col;
866 for (
int r = 0; r < rows; ++r) {
868 while (j < row[r+1]) {
869 if (_Data[j] == .0) {
872 if (i < j) col[i] = col[j], _Data[i] = _Data[j];
880 if (_Size > _NNZ + _MaxNumberOfUnusedEntries) Reserve(_NNZ);
884 template <
class TEntry>
888 if (_Layout == CRS) {
889 nnz = _Row[r+1] - _Row[r];
891 for (
int c = 0; c < _Cols; ++c) {
892 for (
int i = _Col[c]; i != _Col[c+1]; ++i) {
893 if (_Row[i] == r) ++nnz;
901 template <
class TEntry>
905 if (_Layout == CCS) {
906 nnz = _Col[c+1] - _Col[c];
908 for (
int r = 0; r < _Rows; ++r) {
909 for (
int i = _Row[r]; i != _Row[r+1]; ++i) {
910 if (_Col[i] == c) ++nnz;
918 template <
class TEntry>
922 if (_Layout == CRS) {
923 for (
int r = r1; r <= r2; ++r) {
925 while (i != _Row[r+1] && _Col[i] < c1) ++i;
927 while (j != _Row[r+1] && _Col[j] <= c2) ++j;
931 for (
int c = c1; c <= c2; ++c) {
933 while (i != _Col[c+1] && _Row[i] < r1) ++i;
935 while (j != _Col[c+1] && _Row[j] <= r2) ++j;
943 template <
class TEntry>
947 MIRTK_START_TIMING();
949 if (_Layout == CRS) {
950 _Index = Allocate<Array<int> >(_Cols);
951 Array<int> count(_Cols, 0);
952 for (i = 0; i < _NNZ; ++i) {
955 for (j = 0; j < _Cols; ++j) {
956 _Index[j].resize(count[j]);
959 for (i = 0; i < _NNZ; ++i) {
961 _Index[j][count[j]++] = i;
964 _Index = Allocate<Array<int> >(_Rows);
965 Array<int> count(_Rows, 0);
966 for (i = 0; i < _NNZ; ++i) {
969 for (j = 0; j < _Rows; ++j) {
970 _Index[j].resize(count[j]);
973 for (i = 0; i < _NNZ; ++i) {
975 _Index[j][count[j]++] = i;
978 MIRTK_DEBUG_TIMING(10,
"building sparse matrix index");
983 template <
class TEntry>
990 template <
class TEntry>
995 int rows, *col, *row;
996 if (_Layout == CCS) {
1008 for (i = row[r]; i != row[r+1]; ++i) {
1009 if (col[i] > c)
break;
1010 if (col[i] == c)
return _Data[i];
1015 if (_NNZ == _Size) {
1016 Reserve(_Size + _MaxNumberOfUnusedEntries);
1017 if (_Layout == CCS) row = _Col, col = _Row;
1018 else row = _Row, col = _Col;
1021 for (
int j = _NNZ; j > i; --j) {
1022 col [j] = col [j-1];
1023 _Data[j] = _Data[j-1];
1026 _Data[i] = TEntry(0);
1027 for (
int j = r + 1; j < rows; ++j) ++row[j];
1033 template <
class TEntry>
1037 if (v == TEntry(0)) {
1039 int rows, *col, *row;
1040 if (_Layout == CCS) {
1051 for (
int i = row[r]; i != row[r+1]; ++i) {
1052 if (col[i] < c)
continue;
1055 for (
int j = i + 1; j < _NNZ; ++j) {
1056 col [j-1] = col [j];
1057 _Data[j-1] = _Data[j];
1059 for (
int j = r + 1; j < rows; ++j) --row[j];
1060 row[rows] = (--_NNZ);
1061 if (_Size > _NNZ + _MaxNumberOfUnusedEntries) {
1062 Reserve(_NNZ + _MaxNumberOfUnusedEntries);
1069 this->operator ()(r, c) = v;
1074 template <
class TEntry>
1078 if (_Layout == CRS) {
1079 for (
int i = _Row[r]; i != _Row[r+1]; ++i) {
1080 if (_Col[i] == c)
return _Data[i];
1081 if (_Col[i] > c)
break;
1084 for (
int i = _Col[c]; i != _Col[c+1]; ++i) {
1085 if (_Row[i] == r)
return _Data[i];
1086 if (_Row[i] > r)
break;
1093 template <
class TEntry>
1098 for (
typename Entries::iterator i = row.begin(); i != row.end(); ++i) {
1099 if (i->second == TEntry(0)) {
1100 typename Entries::iterator j = i; --i;
1105 sort(row.begin(), row.end());
1108 if (_Layout == CRS) {
1110 int dnnz =
static_cast<int>(row.size()) - (_Row[r+1] - _Row[r]);
1112 if (_NNZ + dnnz > _Size) Reserve(_NNZ + dnnz);
1118 for (
int j = r + 1; j < _Rows; ++j) _Row[j] += dnnz;
1122 for (
int i = _Row[r+1], j = i - dnnz; i < _NNZ; ++i, ++j) {
1123 _Col [i] = _Col [j];
1124 _Data[i] = _Data[j];
1126 }
else if (dnnz > 0) {
1127 for (
int i = _NNZ - 1, j = i - dnnz; i >= _Row[r+1]; --i, --j) {
1128 _Col [i] = _Col [j];
1129 _Data[i] = _Data[j];
1133 bool index_invalid = (dnnz != 0);
1134 typename Entries::const_iterator entry = row.begin();
1135 for (
int i = _Row[r]; i != _Row[r+1]; ++i, ++entry) {
1136 if (_Col[i] != entry->first) {
1137 _Col[i] = entry->first;
1138 index_invalid =
true;
1140 _Data[i] = entry->second;
1145 if (_NNZ < _Size - _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1148 if (_NNZ + static_cast<int>(row.size()) > _Size) {
1149 Reserve(_NNZ + static_cast<int>(row.size()));
1152 typename Entries::const_iterator entry = row.begin();
1153 for (; entry != row.end(); ++entry) {
1154 this->operator ()(r, entry->first) = entry->second;
1157 if (_Size > _NNZ + _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1162 template <
class TEntry>
1165 if (_Layout == CRS) {
1166 row.resize(_Row[r+1] - _Row[r]);
1167 for (
int i = _Row[r], c = 0; i != _Row[r+1]; ++i, ++c) {
1168 row[c] = MakePair(_Col[i], _Data[i]);
1173 row.resize(_Index[r].size());
1174 for (
size_t j = 0; j < _Index[r].size(); ++j) {
1176 while (i >= _Col[c+1]) ++c;
1177 row[j] = MakePair(c, _Data[i]);
1181 for (
int c = 0; c < _Cols; ++c) {
1182 for (
int i = _Col[c]; i != _Col[c+1]; ++i) {
1183 if (_Row[i] < r)
continue;
1184 if (_Row[i] == r) row.push_back(MakePair(c, _Data[i]));
1193 template <
class TEntry>
1203 template <
class TEntry>
1208 for (
typename Entries::iterator i = col.begin(); i != col.end(); ++i) {
1209 if (i->second == TEntry(0)) {
1210 typename Entries::iterator j = i; --i;
1215 sort(col.begin(), col.end());
1218 if (_Layout == CCS) {
1220 int dnnz =
static_cast<int>(col.size()) - (_Col[c+1] - _Col[c]);
1222 if (_NNZ + dnnz > _Size) Reserve(_NNZ + dnnz);
1228 for (
int j = c + 1; j < _Cols; ++j) _Col[j] += dnnz;
1232 for (
int i = _Col[c+1], j = i - dnnz; i < _NNZ; ++i, ++j) {
1233 _Row [i] = _Row [j];
1234 _Data[i] = _Data[j];
1236 }
else if (dnnz > 0) {
1237 for (
int i = _NNZ - 1, j = i - dnnz; i >= _Col[c+1]; --i, --j) {
1238 _Row [i] = _Row [j];
1239 _Data[i] = _Data[j];
1243 bool index_invalid = (dnnz != 0);
1244 typename Entries::const_iterator entry = col.begin();
1245 for (
int i = _Col[c]; i != _Col[c+1]; ++i, ++entry) {
1246 if (_Row[i] != entry->first) {
1247 _Row[i] = entry->first;
1248 index_invalid =
true;
1250 _Data[i] = entry->second;
1255 if (_NNZ < _Size - _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1258 if (_NNZ + static_cast<int>(col.size()) > _Size) {
1259 Reserve(_NNZ + static_cast<int>(col.size()));
1262 typename Entries::const_iterator entry = col.begin();
1263 for (; entry != col.end(); ++entry) {
1264 this->operator ()(entry->first, c) = entry->second;
1267 if (_Size > _NNZ + _MaxNumberOfUnusedEntries) Reserve(_NNZ);
1272 template <
class TEntry>
1279 template <
class TEntry>
1282 if (_Layout == CRS) {
1285 col.resize(_Index[c].size());
1286 for (
size_t j = 0; j < _Index[c].size(); ++j) {
1288 while (i >= _Row[r+1]) ++r;
1289 col[j] = MakePair(r, _Data[i]);
1293 for (
int r = 0; r < _Rows; ++r) {
1294 for (
int i = _Row[r]; i != _Row[r+1]; ++i) {
1295 if (_Col[i] < c)
continue;
1296 if (_Col[i] == c) col.push_back(MakePair(r, _Data[i]));
1302 col.resize(_Col[c+1] - _Col[c]);
1303 for (
int i = _Col[c], r = 0; i != _Col[c+1]; ++i, ++r) {
1304 col[r] = MakePair(_Row[i], _Data[i]);
1310 template <
class TEntry>
1317 template <
class TEntry>
1327 template <
class TEntry>
1335 template <
class TEntry>
1338 if (_Rows != _Cols) {
1339 cerr <<
"GenericSparseMatrix::GetDiag: Matrix must be square" << endl;
1343 for (
int i = 0; i < _Rows; ++i) d(i) = this->
Get(i, i);
1347 template <
class TEntry>
1356 template <
class TEntry>
1359 if (_Rows != _Cols) {
1360 cerr <<
"GenericSparseMatrix::Diag: Matrix must be square" << endl;
1363 if (d.
Rows() != _Rows) {
1364 cerr <<
"GenericSparseMatrix::Diag: Invalid vector size" << endl;
1368 int rows, *col, *row;
1369 if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
1370 else rows = _Rows, row = _Row, col = _Col;
1372 int i, j, r, dnnz = 0;
1373 for (r = 0; r < rows; ++r) {
1376 while (i < row[r+1] && col[i] < r) ++i;
1377 if (i == row[r+1] || col[i] != r) ++dnnz;
1381 if (_NNZ + dnnz > _Size) {
1382 Reserve(_NNZ + dnnz);
1383 if (_Layout == CCS) row = _Col, col = _Row;
1384 else row = _Row, col = _Col;
1391 i = _NNZ - 1 - dnnz;
1394 while (r >= 0 && i < j) {
1396 for (; i >= row[r] && col[i] > r; --i, --j) {
1397 col[j] = col[i], _Data[j] = _Data[i];
1400 if (i >= row[r] && col[i] == r) {
1401 col[j] = r, _Data[j] =
static_cast<TEntry
>(d(r)), --i, --j;
1402 }
else if (d(r) != .0) {
1403 col[j] = r, _Data[j] =
static_cast<TEntry
>(d(r)), --j;
1407 for (; i >= row[r]; --i, --j) {
1408 col[j] = col[i], _Data[j] = _Data[i];
1419 mirtkAssert(i == j,
"no more missing diagonal entries");
1423 while (i >= row[r] && col[i] > r) --i;
1425 mirtkAssert(i >= row[r] && col[i] == r,
"diagonal entry must exist");
1426 _Data[i] =
static_cast<TEntry
>(d(r));
1438 template <
class TEntry>
1441 Diag(
Vector(_Rows, static_cast<double>(d)));
1445 template <
class TEntry>
1450 cerr <<
"GenericSparseMatrix::Sub (getter): Not implemented" << endl;
1456 template <
class TEntry>
1460 MIRTK_START_TIMING();
1461 int r2 = r1 + sub.Rows() - 1;
1462 int c2 = c1 + sub.Cols() - 1;
1463 if (r2 >= _Rows || c2 >= _Cols) {
1464 cerr <<
"GenericSparseMatrix::Sub (setter): " << sub.Rows() <<
" x " << sub.Cols()
1465 <<
" submatrix starting at (" << r1 <<
", " << c1 <<
") exceeds matrix index range [0, " 1466 << _Rows-1 <<
"] x [0, " << _Cols-1 <<
"]" << endl;
1469 if (_Layout != sub.
Layout()) {
1471 cerr <<
"GenericSparseMatrix::Sub (setter): Submatrix must have same layout as this matrix" << endl;
1475 const int dif_nnz = sub._NNZ - this->SubNNZ(r1, c1, r2, c2);
1476 const int new_nnz = _NNZ + dif_nnz;
1478 if (new_nnz > _Size) Reserve(new_nnz);
1480 int rows, *col, *row;
1481 const int *sub_col, *sub_row;
1482 if (_Layout == CCS) {
1498 int i, k, k1, k2, j = new_nnz - 1;
1500 for (i = _NNZ - 1; i >= row[r2 + 1]; --i, --j) {
1502 _Data[j] = _Data[i];
1504 for (
int r = r2 + 1; r < rows; ++r) row[r] += dif_nnz;
1505 row[rows] = _NNZ = new_nnz;
1507 for (
int r = r2; r >= r1; --r) {
1509 for (i = row[r+1] - 1; i >= row[r] && col[i] > c2; --i, --j) {
1511 _Data[j] = _Data[i];
1514 while (i >= row[r] && col[i] >= c1) --i;
1516 k1 = sub_row[r - r1];
1517 k2 = sub_row[r - r1 + 1] - 1;
1518 for (k = k2; k >= k1; --k, --j) {
1519 col [j] = c1 + sub_col[k];
1520 _Data[j] = sub.
_Data[k];
1523 for (; i >= row[r]; --i, --j) {
1525 _Data[j] = _Data[i];
1530 MIRTK_DEBUG_TIMING(7,
"GenericSparseMatrix::Sub (setter)");
1534 template <
class TEntry>
1538 if (_Layout == CRS) {
1539 if (_Row) memset(_Row, 0, (_Rows + 1) *
sizeof(
int));
1543 if (_Col) memset(_Col, 0, (_Cols + 1) *
sizeof(
int));
1546 _Rows = _Cols = _Size = _NNZ = 0;
1550 template <
class TEntry>
1554 if (_Layout == CRS) {
1555 if (_Row) memset(_Row, 0, (_Rows + 1) *
sizeof(
int));
1557 if (_Col) memset(_Col, 0, (_Cols + 1) *
sizeof(
int));
1567 template <
class TEntry>
1572 Array<Entries> entries;
1573 if (_Layout == CRS) {
1574 entries.resize(_Cols);
1575 for (
int c = 0; c < _Cols; ++c) entries[c] = Col(c);
1578 entries.resize(_Rows);
1579 for (
int r = 0; r < _Rows; ++r) entries[r] = Row(r);
1582 Initialize(_Cols, _Rows, entries);
1584 if (_Layout == CRS) _Layout = CCS;
1591 template <
class TEntry>
1594 TEntry s = TEntry(0);
1595 if (_Layout == CRS) {
1596 for (
int i = _Row[r]; i != _Row[r+1]; ++i) s += _Data[i];
1599 for (
size_t c = 0; c < _Index[r].size(); ++c) {
1600 s += _Data[_Index[r][c]];
1603 for (
int c = 0; c < _Cols; ++c) {
1604 for (
int i = _Col[c]; i != _Col[c+1]; ++i) {
1605 if (_Row[i] < r)
continue;
1606 if (_Row[i] == r) s += _Data[i];
1616 template <
class TEntry>
1619 TEntry s = TEntry(0);
1620 if (_Layout == CRS) {
1622 for (
size_t r = 0; r < _Index[c].size(); ++r) {
1623 s += _Data[_Index[c][r]];
1626 for (
int r = 0; r < _Rows; ++r) {
1627 for (
int i = _Row[r]; i != _Row[r+1]; ++i) {
1628 if (_Col[i] < c)
continue;
1629 if (_Col[i] == c) s += _Data[i];
1635 for (
int i = _Col[c]; i != _Col[c+1]; ++i) s += _Data[i];
1641 template <
class TEntry>
1648 template <
class TEntry>
1651 const TEntry zero(0);
1652 if (_Layout == CRS) {
1653 for (
int r = 0; r < _Rows; ++r) {
1655 for (
int i = _Row[r]; i != _Row[r+1]; ++i) w[r] += _Data[i] * v[_Col[i]];
1660 for (
int r = 0; r < _Rows; ++r) {
1662 for (
size_t c = 0; c < _Index[r].size(); ++c) {
1664 w[r] += _Data[i] * v[_Col[i]];
1668 for (
int r = 0; r < _Rows; ++r) w[r] = zero;
1669 for (
int c = 0; c < _Cols; ++c) {
1670 for (
int i = _Col[c]; i != _Col[c+1]; ++i) {
1671 w[_Row[c]] += _Data[i] * v[c];
1679 template <
class TEntry>
1682 for (
int i = 0; i < _NNZ; ++i) _Data[i] *= s;
1687 template <
class TEntry>
1690 for (
int i = 0; i < _NNZ; ++i) _Data[i] /= s;
1695 template <
class TEntry>
1703 template <
class TEntry>
1711 template <
class TEntry>
1714 if (_Layout == CRS) {
1715 for (
int i = _Row[r]; i != _Row[r+1]; ++i) _Data[i] *= s;
1718 for (
size_t c = 0; c < _Index[r].size(); ++c) {
1719 _Data[_Index[r][c]] *= s;
1722 for (
int c = 0; c < _Cols; ++c) {
1723 for (
int i = _Col[c]; i != _Col[c+1]; ++i) {
1724 if (_Row[i] < r)
continue;
1725 if (_Row[i] == r) _Data[i] *= s;
1735 template <
class TEntry>
1738 if (_Layout == CRS) {
1740 for (
size_t r = 0; r < _Index[c].size(); ++r) {
1741 _Data[_Index[c][r]] *= s;
1744 for (
int r = 0; r < _Rows; ++r) {
1745 for (
int i = _Row[r]; i != _Row[r+1]; ++i) {
1746 if (_Col[i] < c)
continue;
1747 if (_Col[i] == c) _Data[i] *= s;
1753 for (
int i = _Col[c]; i != _Col[c+1]; ++i) _Data[i] *= s;
1759 template <
class TEntry>
1762 return ScaleColumn(c, s);
1766 template <
class TEntry>
1769 if (_Rows != _Cols)
return false;
1771 int rows, *col, *row;
1772 if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
1773 else rows = _Rows, row = _Row, col = _Col;
1775 int i, iend, j, jend, r, c;
1776 for (r = 0; r < rows-1; ++r) {
1779 while (i < iend && col[i] < r) ++i;
1784 while (j < jend && col[j] < r) ++j;
1785 if (j == jend || col[j] != r || !
fequal(_Data[i], _Data[j])) {
1795 template <
class TEntry>
1798 if (_Rows != _Cols) {
1799 cerr <<
"GenericSparseMatrix::MakeSymmetric: Matrix must be square" << endl;
1803 int rows, *col, *row;
1804 if (_Layout == CCS) rows = _Cols, row = _Col, col = _Row;
1805 else rows = _Rows, row = _Row, col = _Col;
1807 int i, j, k, r, c, dnnz = 0;
1808 for (r = 0; r < rows; ++r) {
1809 for (i = row[r]; i < row[r+1]; ++i) {
1812 while (j < row[c+1] && col[j] < r) ++j;
1813 if (j < row[c+1] && col[j] != r) ++dnnz;
1817 if (_NNZ + dnnz > _Size) {
1818 Reserve(_NNZ + dnnz);
1819 if (_Layout == CCS) row = _Col, col = _Row;
1820 else row = _Row, col = _Col;
1825 for (r = 0; r < rows-1; ++r) {
1827 while (i < row[r+1] && col[i] < r) ++i;
1828 while (i < row[r+1]) {
1831 while (j < row[c+1] && col[j] < r) ++j;
1832 if (j < row[c+1] && col[j] == r) {
1833 _Data[i] = _Data[j] = (_Data[i] + _Data[j]) / 2;
1835 if (!extent) _Data[i] = _Data[i] / 2;
1836 for (k = _NNZ; k > j; --k) {
1837 col [k] = col [k-1];
1838 _Data[k] = _Data[k-1];
1841 _Data[j] = _Data[i];
1842 for (k = c + 1; k < rows; ++k) ++row[k];
1854 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 1857 template <
class TEntry>
1860 Matlab::Initialize();
1861 mxArray *sa = mxCreateSparse(_Rows, _Cols, _NNZ, mxREAL);
1862 mwIndex *ir = mxGetIr(sa);
1863 mwIndex *jc = mxGetJc(sa);
1864 double *pr = mxGetPr(sa);
1865 if (_Layout == CCS) {
1866 for (
int c = 0; c < _Cols; ++c) {
1869 for (
int i = 0; i < _NNZ; ++i) {
1876 for (
int c = 0; c < _Cols; ++c) {
1879 typename Entries::const_iterator entry;
1880 for (entry = col.begin(); entry != col.end(); ++entry, ++i) {
1881 ir[i] = entry->first;
1882 pr[i] = entry->second;
1890 #endif // MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 1893 template <
class TEntry>
1896 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 1897 Matlab::Initialize();
1898 MATFile *fp = matOpen(fname,
"r");
1899 if (fp == NULL)
return false;
1900 mxArray *pm = matGetVariable(fp, varname);
1907 return (matClose(fp) == 0);
1909 cerr <<
"GenericSparseMatrix::ReadMAT: Must be compiled WITH_MATLAB enabled" << endl;
1915 template <
class TEntry>
1918 #if MIRTK_Numerics_WITH_MATLAB && defined(HAVE_MATLAB) 1919 Matlab::Initialize();
1920 MATFile *fp = matOpen(fname,
"w");
1921 if (fp == NULL)
return false;
1922 mxArray *m = MxArray();
1923 if (matPutVariable(fp, varname, m) != 0) {
1929 return (matClose(fp) == 0);
1931 cerr <<
"GenericSparseMatrix::WriteMAT: Must be compiled WITH_MATLAB enabled" << endl;
1937 template <
class TEntry>
1943 of << varname <<
"_r = [";
1944 if (_Layout == CRS) {
1945 for (
int r = 1; r <= _Rows; ++r) {
1946 for (
int i = _Row[r-1]; i != _Row[r]; ++i) {
1951 for (
int i = 0; i < _NNZ; ++i) {
1952 of << (_Row[i] + 1) <<
" ";
1957 of << varname <<
"_c = [";
1958 if (_Layout == CCS) {
1959 for (
int c = 1; c <= _Cols; ++c) {
1960 for (
int i = _Col[c-1]; i != _Col[c]; ++i) {
1965 for (
int i = 0; i < _NNZ; ++i) {
1966 of << (_Col[i] + 1) <<
" ";
1971 of << varname <<
"_v = [";
1972 for (
int i = 0; i < _NNZ; ++i) {
1973 of << _Data[i] <<
" ";
1976 of << varname <<
" = sparse(" << varname <<
"_r, " << varname <<
"_c, " << varname <<
"_v, ";
1977 of << _Rows <<
", " << _Cols <<
", " << _NNZ <<
");" << endl;
1989 #if MIRTK_USE_FLOAT_BY_DEFAULT 1992 typedef SparseDoubleMatrix SparseMatrix;
1998 #endif // MIRTK_SparseMatrix_H int GetRawData(int *&, int *&, TEntry *&) const
Get raw access to index and data arrays.
bool WriteMAT(const char *, const char *="A") const
virtual ~GenericSparseMatrix()
Destructor.
void Initialize(int, int=0, int=0)
Initialize sparse matrix.
void GetDiag(Vector &d) const
Get diagonal values.
void CopyAttributes(const GenericSparseMatrix< TOtherEntry > &)
Copy other matrix, used by copy constructor and assignment operator only.
bool IsSymmetric() const
Whether this matrix is symmetric.
void Zero()
Set all non-zero entries to zero (i.e., remove)
GenericSparseMatrix & ScaleCol(int, EntryType)
GenericSparseMatrix(StorageLayout=CCS)
Default constructor.
string Get(const ParameterList ¶ms, string name)
Get parameter value from parameters list.
GenericSparseMatrix operator*(EntryType) const
Multiply by a scalar.
GenericSparseMatrix & ScaleRow(int, EntryType)
mirtkAttributeMacro(int, Size)
Number of allocated elements.
mirtkPublicAttributeMacro(int, MaxNumberOfUnusedEntries)
Maximum number of unused entries, i.e., (_Size - _NNZ)
GenericSparseMatrix operator/(EntryType) const
Divide by a scalar.
GenericSparseMatrix Sub(int, int, int, int) const
Get non-zero entries of specified submatrix.
void GetRow(int, Entries &) const
GenericSparseMatrix & operator*=(EntryType)
Multiply by a scalar in-place.
void MultAv(EntryType [], EntryType []) const
void CheckEntries(Entries &) const
Check non-zero entries, sort them, remove zero entries, and sum up duplicates.
GenericSparseMatrix & operator=(const GenericSparseMatrix< TOtherEntry > &)
Assignment operator.
MIRTKCU_API bool fequal(double a, double b, double tol=1e-12)
void Put(int, int, EntryType)
void Col(int, Entries &, bool=false)
GenericSparseMatrix & ScaleColumn(int, EntryType)
bool ReadMAT(const char *, const char *="A")
int Eigenvalues(Vector &v, int k, const char *sigma="LM", int p=0, double tol=.0, int maxit=0, Vector *v0=NULL) const
EntryType & operator()(int, int=-1)
EntryType Get(int, int=-1) const
Get value.
void Row(int, Entries &, bool=false)
int Rows() const
Returns number of rows.
void GetCol(int, Entries &) const
EntryType ColSum(int) const
void RemoveZeros()
Remove any zero entries.
TEntry EntryType
Type of matrix entry values.
int RowNNZ(int) const
Number of non-zero entries in specified row.
void Deallocate(Type *&p)
Deallocate 1D array.
EntryType * _Data
Non-zero entries.
void WriteMFile(const char *, const char *="A") const
void ClearIndex()
Free memory needed for precomputed indices.
void Reserve(int)
Reserve more memory.
int SubNNZ(int, int, int, int) const
Number of non-zero entries in specified submatrix.
int Eigenvectors(Matrix &E, int k, const char *sigma="LM", int p=0, double tol=.0, int maxit=0, Vector *v0=NULL) const
GenericSparseMatrix & operator/=(EntryType)
Divide by a scalar in-place.
EntryType ColumnSum(int) const
EntryType RowSum(int) const
void MakeSymmetric(bool extent=false)
int ColNNZ(int) const
Number of non-zero entries in specified column.
TEntry * RawPointer(int=0)
Get raw access to non-zero values.
Vector Diag() const
Get diagonal values.
Pair< int, TEntry > Entry
Type of non-zero entry.
void Column(int, Entries &, bool=false)
mirtkReadOnlyAttributeMacro(enum StorageLayout, Layout)
Storage layout.
Array< Entry > Entries
List of non-zero entries.
virtual void Clear()
Free all non-zero entries.
void Layout(StorageLayout)
Change storage layout.
void Transpose(bool keep_layout=false)
void GetColumn(int, Entries &) const
void Initialize(int)
Intialize matrix with number of rows.