37 #define G_CHOLESKY "GSparseSymbolic::cholesky_symbolic_analysis(int, "\
39 #define G_CS_AMD "GSparseSymbolic::cs_amd(int, GMatrixSparse*)"
42 #define CS_MIN(a,b) (((a) < (b)) ? (a) : (b))
43 #define CS_MAX(a,b) (((a) > (b)) ? (a) : (b))
44 #define CS_FLIP(i) (-(i)-2)
45 #define HEAD(k,j) (ata ? head [k] : j)
46 #define NEXT(J) (ata ? next [J] : -1)
91 if (
m_q != NULL)
delete []
m_q;
117 if (
m_q != NULL)
delete []
m_q;
145 for (
int i = 0; i < s.
m_n_pinv; ++i) {
154 for (
int i = 0; i < s.
m_n_q; ++i) {
172 for (
int i = 0; i < s.
m_n_cp; ++i) {
213 #if defined(G_DEBUG_SPARSE_CHOLESKY)
214 std::cout << endl <<
"GSparseSymbolic::cholesky_symbolic_analysis entered" << std::endl;
215 std::cout <<
" order ......................: " << order << std::endl;
216 std::cout <<
" number of rows .............: " << m.
m_rows << std::endl;
217 std::cout <<
" number of columns ..........: " << m.
m_cols << std::endl;
218 std::cout <<
" number of non-zero elements : " << m.
m_elements << std::endl;
223 if (
m_q != NULL)
delete []
m_q;
244 if (order < 0 || order > 1) {
245 std::string msg =
"Invalid ordering type "+
gammalib::str(order)+
246 "specified. The ordering type must be comprised in "
247 "[0,1]. Please specify a valid ordering type.";
255 int* P =
cs_amd(order, &m);
256 #if defined(G_DEBUG_SPARSE_CHOLESKY)
257 std::cout <<
" AMD ordering permutation (" << P <<
")" << std::endl;
259 for (
int i = 0; i < n; ++i) {
260 std::cout <<
" " << P[i];
262 std::cout << std::endl;
270 #if defined(G_DEBUG_SPARSE_CHOLESKY)
271 std::cout <<
" Inverse permutation (" <<
m_pinv <<
")" << std::endl;
273 for (
int i = 0; i < n; ++i) {
274 std::cout <<
" " <<
m_pinv[i];
276 std::cout << std::endl;
287 #if defined(G_DEBUG_SPARSE_CHOLESKY)
288 std::cout <<
" C = spones(triu(A(P,P))) " << C << std::endl;
294 #if defined(G_DEBUG_SPARSE_CHOLESKY)
295 std::cout <<
" Elimination tree (" <<
m_parent <<
")" << std::endl;
297 for (
int i = 0; i < n; ++i) {
300 std::cout << std::endl;
307 #if defined(G_DEBUG_SPARSE_CHOLESKY)
308 std::cout <<
" Post ordered elimination tree (" << post <<
")" << std::endl;
310 for (
int i = 0; i < n; ++i) {
311 std::cout <<
" " << post[i];
313 std::cout << std::endl;
320 #if defined(G_DEBUG_SPARSE_CHOLESKY)
321 std::cout <<
" Column counts (" << c <<
")" << std::endl;
323 for (
int i = 0; i < n; ++i) {
324 std::cout <<
" " << c[i];
326 std::cout << std::endl;
341 #if defined(G_DEBUG_SPARSE_CHOLESKY)
342 std::cout <<
" Column pointers for L (" <<
m_cp <<
")" << std::endl;
344 for (
int i = 0; i <
m_n_cp; ++i) {
345 std::cout <<
" " <<
m_cp[i];
347 std::cout << std::endl;
349 std::cout <<
" Number of non-zero elements in L: " <<
m_lnz << std::endl;
362 if (
m_q != NULL)
delete []
m_q;
384 #if defined(G_DEBUG_SPARSE_CHOLESKY)
385 std::cout <<
"GSparseSymbolic::cholesky_symbolic_analysis finished" << std::endl;
419 if (order < 0 || order > 3) {
420 std::string msg =
"Invalid ordering type "+
gammalib::str(order)+
421 "specified. The ordering type must be comprised in "
422 "[0,3]. Please specify a valid ordering type.";
427 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
428 std::cout << std::endl <<
"GSparseSymbolic::cs_amd entered" << std::endl;
429 std::cout <<
" order ......................: " << order << std::endl;
430 std::cout <<
" number of rows .............: " << A->
m_rows << std::endl;
431 std::cout <<
" number of columns ..........: " << A->
m_cols << std::endl;
432 std::cout <<
" number of non-zero elements : " << A->
m_elements << std::endl;
437 int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1,
438 k2, k3, jlast, ln, mindeg = 0, nvi, nvj, nvk, mark, wnvi,
439 ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q;
452 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
453 std::cout <<
" Step 1: Construct matrix C" << std::endl;
469 dense = (int)
CS_MAX(16, 10 *
sqrt((
double)n));
470 dense =
CS_MIN(n-2, dense);
473 if (order == 1 && n == m) {
480 else if (order == 2) {
487 for (p2 = 0, j = 0; j < m; j++) {
490 if (ATp[j+1] - p > dense) {
493 for ( ; p < ATp[j+1]; p++) {
521 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
522 std::cout <<
" Matrix C " << C << std::endl;
529 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
530 std::cout <<
" Dropped diagonal entries from matrix C " << C << std::endl;
538 int* P =
new int[n+1];
541 int wrk_size = 8*(n+1);
542 int* wrk_int =
new int[wrk_size];
545 int elbow_room = cnz/5 + 2*n;
555 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
556 std::cout <<
" Added elbow room to matrix C " << C << std::endl;
561 int* nv = wrk_int + (n+1);
562 int* next = wrk_int + 2*(n+1);
563 int* head = wrk_int + 3*(n+1);
564 int* elen = wrk_int + 4*(n+1);
565 int* degree = wrk_int + 5*(n+1);
566 int* w = wrk_int + 6*(n+1);
567 int* hhead = wrk_int + 7*(n+1);
576 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
577 std::cout <<
" Step 2: Initialize quotient graph" << std::endl;
581 for (k = 0 ; k < n ; k++) {
582 len[k] = Cp[k+1] - Cp[k];
587 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
588 std::cout <<
" Non-zero elements per column: ";
589 for (k = 0 ; k <= n ; k++) {
590 std::cout <<
" " << len[k];
592 std::cout << std::endl;
596 for (i = 0 ; i <= n ; i++) {
621 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
622 std::cout <<
" Step 3: Initialize degree lists" << std::endl;
626 for (i = 0 ; i < n ; i++) {
640 else if (d > dense) {
650 if (head[d] != -1) last[head[d]] = i;
663 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
664 std::cout <<
" Step 4: Build permutations" << std::endl;
671 for (k = -1; mindeg < n && (k = head [mindeg]) == -1; mindeg++) ;
672 if (next[k] != -1) last [next[k]] = -1;
673 head[mindeg] = next[k];
679 if (elenk > 0 && cnz + mindeg >= nzmax) {
682 for (j = 0; j < n; j++) {
684 if ((p = Cp[j]) >= 0) {
691 for (q = 0, p = 0; p < cnz; ) {
693 if ((j =
CS_FLIP(Ci[p++])) >= 0) {
696 for (k3 = 0; k3 < len[j]-1; k3++) {
709 pk1 = (elenk == 0) ? p : cnz;
711 for (k1 = 1; k1 <= elenk + 1; k1++) {
726 for (k2 = 1 ; k2 <= ln ; k2++) {
728 if ((nvi = nv [i]) <= 0) {
735 last[next[i]] = last[i];
740 next[last[i]] = next[i];
743 head[degree[i]] = next[i];
768 for (pk = pk1 ; pk < pk2 ; pk++) {
771 if ((eln = elen[i]) <= 0) {
778 for (p = Cp[i]; p <= Cp[i] + eln - 1; p++) {
783 else if (w[e] != 0) {
784 w[e] = degree[e] + wnvi;
791 for (pk = pk1; pk < pk2; pk++) {
795 p2 = p1 + elen [i] - 1;
799 for (h = 0, d = 0, p = p1 ; p <= p2 ; p++) {
817 elen[i] = pn - p1 + 1;
822 for (p = p2 + 1 ; p < p4 ; p++) {
824 if ((nvj = nv[j]) <= 0) {
843 degree[i] =
CS_MIN(degree[i], d);
847 len[i] = pn - p1 + 1;
858 lemax =
CS_MAX(lemax, dk);
861 mark =
cs_wclear(mark+lemax, lemax, w, n);
864 for (pk = pk1 ; pk < pk2 ; pk++) {
875 for ( ; i != -1 && next[i] != -1 ; i = next[i], mark++) {
878 for (p = Cp[i]+1 ; p <= Cp[i] + ln-1 ; p++) {
884 for (j = next[i]; j != -1; ) {
885 ok = (len[j] == ln) && (elen[j] == eln);
886 for (p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++) {
887 if (w[Ci[p]] != mark) {
913 for (p = pk1, pk = pk1; pk < pk2; pk++) {
915 if ((nvi = -nv[i]) <= 0) {
919 d = degree[i] + dk - nvi;
920 d =
CS_MIN(d, n - nel - nvi);
927 mindeg =
CS_MIN(mindeg, d);
936 if ((len [k] = p-pk1) == 0) {
952 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
953 std::cout <<
" Step 5: Postordering" << std::endl;
957 for (i = 0; i < n; i++) {
960 for (j = 0 ; j <= n ; j++) {
965 for (j = n ; j >= 0 ; j--) {
969 next[j] = head [Cp[j]];
974 for (e = n ; e >= 0 ; e--) {
979 next[e] = head[Cp[e]];
990 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
991 std::cout <<
" Step 6: Postorder the assembly tree" << std::endl;
995 for (k = 0, i = 0 ; i <= n ; i++) {
997 k =
cs_tdfs(i, k, head, next, P, w);
1005 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
1006 std::cout <<
" Permutation:" << std::endl;
1007 for (i = 0; i < n; ++i) {
1008 std::cout <<
" " << P[i];
1011 std::cout <<
"GSparseSymbolic::cs_amd finished" << std::endl;
1036 int i, j, k, J, p, q, jleaf;
1040 if (!parent || !post) {
1049 int* colcount =
new int[n];
1050 int* delta = colcount;
1053 int wrk_size = 4*n + (ata ? (n+m+1) : 0);
1054 int* wrk_int =
new int[wrk_size];
1060 int* ancestor = wrk_int;
1061 int* maxfirst = wrk_int + n;
1062 int* prevleaf = wrk_int + 2*n;
1063 int* first = wrk_int + 3*n;
1066 for (k = 0; k < wrk_size; ++k) {
1071 for (k = 0; k < n; k++) {
1073 delta[j] = (first[j] == -1) ? 1 : 0;
1074 for ( ; j != -1 && first[j] == -1; j = parent[j]) {
1089 init_ata(&AT, post, wrk_int, &head, &next);
1093 for (i = 0; i < n; i++) {
1098 for (k = 0; k < n; k++) {
1100 if (parent[j] != -1) {
1103 for (J =
HEAD(k,j); J != -1; J =
NEXT(J)) {
1106 for (p = ATp[J]; p < ATp[J+1]; p++) {
1108 q =
cs_leaf(i, j, first, maxfirst, prevleaf, ancestor, &jleaf);
1117 if (parent[j] != -1) {
1118 ancestor[j] = parent[j];
1123 for (j = 0; j < n; j++) {
1124 if (parent[j] != -1) {
1125 colcount[parent[j]] += colcount[j];
1156 int* parent =
new int[n];
1159 int wrk_size = n + (ata ? m : 0);
1160 int* wrk_int =
new int[wrk_size];
1163 int* ancestor = wrk_int;
1164 int* prev = wrk_int + n;
1168 for (i = 0; i < m ; ++i) {
1174 for (k = 0; k < n; ++k) {
1188 for ( ; i != -1 && i < k; i = inext) {
1189 inext = ancestor[i];
1223 int(*fkeep)(
int,
int,
double,
void*),
1241 if (Ap != NULL && Ai != NULL && Ax != NULL) {
1244 for (
int j = 0; j < n; j++) {
1247 for ( ; p < Ap[j+1] ; p++) {
1248 if (fkeep(Ai[p], j, Ax ? Ax[p] : 1, other)) {
1295 if (!first || !maxfirst || !prevleaf || !ancestor || !jleaf) {
1306 if (i <= j || first[j] <= maxfirst[i]) {
1311 maxfirst[i] = first[j];
1314 int jprev = prevleaf[i];
1318 *jleaf = (jprev == -1) ? 1: 2;
1326 for (q = jprev; q != ancestor[q]; q = ancestor[q]) ;
1329 for (s = jprev; s != q; s = sparent) {
1330 sparent = ancestor[s];
1357 int* pinv =
new int[n];
1360 for (
int k = 0; k < n; ++k) {
1382 if (!parent || n < 1) {
1387 int* post =
new int[n];
1390 int wrk_size = 3 * n;
1391 int* wrk_int =
new int[wrk_size];
1394 int* head = wrk_int;
1395 int* next = wrk_int + n;
1396 int* stack = wrk_int + 2*n;
1402 for (j = 0 ; j < n ; j++) {
1407 for (j = n-1; j >= 0; j--) {
1410 if (parent[j] == -1) {
1415 next[j] = head[parent[j]];
1416 head[parent[j]] = j;
1421 for (j = 0 ; j < n ; j++) {
1424 if (parent[j] != -1) {
1429 k =
cs_tdfs(j, k, head, next, post, stack);
1462 if (!head || !next || !post || !stack) {
1528 *head = wrk_int + 4*n;
1529 *next = wrk_int + 5*n+1;
1532 for (k = 0 ; k < n ; k++) {
1533 wrk_int[post[k]] = k;
1537 for (i = 0 ; i < m ; i++) {
1540 for (k = n, p = ATp[i]; p < ATp[i+1]; p++) {
1541 k =
CS_MIN(k,wrk_int[ATi[p]]);
1545 (*next)[i] = (*head)[k];
1586 if (mark < 2 || (mark + lemax < 0)) {
1587 for (
int k = 0; k < n; k++) {
1612 os <<
"=== GSparseSymbolic ===";
1616 os << std::endl <<
" Inverse permutation (of ";
1617 os << s.
m_n_pinv <<
" elements)" << std::endl;
1618 for (
int i = 0; i < s.
m_n_pinv; ++i) {
1619 os <<
" " << s.
m_pinv[i];
1624 if (s.
m_q != NULL) {
1625 os << std::endl <<
" Fill reducing column permutation (";
1626 os << s.
m_n_cp <<
" elements)" << std::endl;
1627 for (
int i = 0; i < s.
m_n_cp; ++i) {
1628 os <<
" " << s.
m_q[i];
1634 os << std::endl <<
" Elimination tree (";
1635 os << s.
m_n_parent <<
" elements)" << std::endl;
1642 if (s.
m_cp != NULL) {
1643 os << std::endl <<
" Cholesky column pointers/QR row counts (";
1644 os << s.
m_n_cp <<
" elements)" << std::endl;
1645 for (
int i = 0; i < s.
m_n_cp; ++i) {
1646 os <<
" " << s.
m_cp[i];
1652 os << std::endl <<
" leftmost[i] = min(find(A(i,:))) (";
static void init_ata(const GMatrixSparse *AT, const int *post, int *wrk_int, int **head, int **next)
GMatrixSparse cs_symperm(const GMatrixSparse &matrix, const int *pinv)
cs_symperm
void cholesky_symbolic_analysis(int order, const GMatrixSparse &m)
int * cs_post(const int *parent, int n)
int * m_parent
elimination tree for Cholesky and QR
int * m_cp
column pointers for Cholesky, row counts for QR
double m_lnz
entries in L for LU or Cholesky; in V for QR
Sparse matrix class interface definition.
int * m_leftmost
leftmost[i] = min(find(A(i,:))), for QR
GMatrixSparse cs_transpose(const GMatrixSparse &matrix, int values)
int m_rows
Number of rows.
Sparse matrix symbolic analysis class definition.
int cs_leaf(int i, int j, const int *first, int *maxfirst, int *prevleaf, int *ancestor, int *jleaf)
int cs_tdfs(int j, int k, int *head, const int *next, int *post, int *stack)
int m_n_cp
Number of elements in m_cp.
int m_n_parent
Number of elements in m_parent.
static int cs_wclear(int mark, int lemax, int *w, int n)
virtual ~GSparseSymbolic(void)
Destructor.
Sparse matrix symbolic analysis class.
GSparseSymbolic(void)
Void constructor.
GVector sqrt(const GVector &vector)
Computes square root of vector elements.
int m_n_leftmost
Number of elements in m_leftmost.
double * m_data
Matrix data.
int * m_pinv
Inverse row permutation for QR, fill reduce permutation for Cholesky.
GSparseSymbolic & operator=(const GSparseSymbolic &s)
void free_elements(const int &start, const int &num)
Free memory for obsolete matrix elements.
int m_cols
Number of columns.
std::ostream & operator<<(std::ostream &os, const GBase &base)
Output operator.
double cs_cumsum(int *p, int *c, int n)
cs_cumsum
int * m_q
Fill-reducing column permutation for LU and QR.
int * cs_amd(int order, const GMatrixSparse *A)
int * m_rowinx
Row-indices of all elements.
int * cs_counts(const GMatrixSparse *A, const int *parent, const int *post, int ata)
int m_n_q
Number of elements in m_q.
int * cs_etree(const GMatrixSparse *A, int ata)
int * cs_pinv(int const *p, int n)
int m_elements
Number of elements stored in matrix.
double m_unz
entries in U for LU; in R for QR
Sparse matrix class definition.
Exception handler interface definition.
int m_n_pinv
Number of elements in m_pinv.
int cs_fkeep(GMatrixSparse *A, int(*fkeep)(int, int, double, void *), void *other)
cs_fkeep
int m_m2
of rows for QR, after adding fictitious rows
int * m_colstart
Column start indices (m_cols+1)
static int cs_diag(int i, int j, double aij, void *other)
void alloc_elements(int start, const int &num)
Allocate memory for new matrix elements.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.