int CHOLMOD(pack_factor) ( /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) { double *Lx, *Lz ; Int *Lp, *Li, *Lnz, *Lnext ; Int pnew, j, k, pold, len, n, head, tail, grow2 ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start pack", Common)) ; PRINT1 (("PACK factor %d\n", L->is_super)) ; if (L->xtype == CHOLMOD_PATTERN || L->is_super) { /* nothing to do unless L is simplicial numeric */ return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* pack */ /* ---------------------------------------------------------------------- */ grow2 = Common->grow2 ; PRINT1 (("\nPACK grow2 "ID"\n", grow2)) ; pnew = 0 ; n = L->n ; Lp = L->p ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lnz = L->nz ; Lnext = L->next ; head = n+1 ; tail = n ; for (j = Lnext [head] ; j != tail ; j = Lnext [j]) { /* pack column j */ pold = Lp [j] ; len = Lnz [j] ; ASSERT (len > 0) ; PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ; if (pnew < pold) { PRINT2 ((" pack this column\n")) ; for (k = 0 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; } if (L->xtype == CHOLMOD_REAL) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for (k = 0 ; k < len ; k++) { Lx [2*(pnew + k) ] = Lx [2*(pold + k) ] ; Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ; } } else if (L->xtype == CHOLMOD_ZOMPLEX) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; Lz [pnew + k] = Lz [pold + k] ; } } Lp [j] = pnew ; } len = MIN (len + grow2, n - j) ; pnew = MIN (Lp [j] + len, Lp [Lnext [j]]) ; } PRINT2 (("final pnew = "ID"\n", pnew)) ; return (TRUE) ; }
void cctest (cholmod_sparse *A) { double knobs [CCOLAMD_KNOBS], knobs2 [CCOLAMD_KNOBS] ; Int *P, *Cmember, *Cp, *Ci, *Front_npivcol, *Front_nrows, *Front_ncols, *Front_parent, *Front_cols, *InFront, *Si, *Sp ; cholmod_sparse *C, *A2, *B, *S ; Int nrow, ncol, alen, ok, stats [CCOLAMD_STATS], csets, i, nfr, c, p ; size_t s ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ my_srand (42) ; /* RAND reset */ printf ("\nCCOLAMD test\n") ; if (A == NULL) { return ; } if (A->stype) { A2 = CHOLMOD(copy) (A, 0, 0, cm) ; B = A2 ; } else { A2 = NULL ; B = A ; } S = CHOLMOD(copy_sparse) (A, cm) ; nrow = B->nrow ; ncol = B->ncol ; Si = S->i ; Sp = S->p ; /* ---------------------------------------------------------------------- */ /* allocate workspace and Cmember for ccolamd */ /* ---------------------------------------------------------------------- */ P = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; Cmember = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; Front_npivcol = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; Front_nrows = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; Front_ncols = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; Front_parent = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; Front_cols = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; InFront = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; csets = MIN (6, nrow) ; for (i = 0 ; i < nrow ; i++) { Cmember [i] = nrand (csets) ; } CCOLAMD_set_defaults (knobs) ; CCOLAMD_set_defaults (knobs2) ; CCOLAMD_set_defaults (NULL) ; CCOLAMD_report (NULL) ; CSYMAMD_report (NULL) ; alen = CCOLAMD_recommended (B->nzmax, ncol, nrow) ; C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, CHOLMOD_PATTERN, cm) ; Cp = C->p ; Ci = C->i ; /* ---------------------------------------------------------------------- */ /* order with ccolamd */ /* ---------------------------------------------------------------------- */ ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; CHOLMOD(print_sparse) (C, "C for ccolamd", cm) ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, NULL, stats, Cmember) ; CCOLAMD_report (stats) ; OK (ok) ; ok = stats [CCOLAMD_STATUS] ; ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; OK (ok) ; /* permutation returned in C->p, if the ordering succeeded */ /* make sure P obeys the constraints */ OK (check_constraints (Cp, Cmember, nrow)) ; /* ---------------------------------------------------------------------- */ /* order with ccolamd2 */ /* ---------------------------------------------------------------------- */ ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; ok = CCOLAMD_2 (ncol, nrow, alen, Ci, Cp, NULL, stats, Front_npivcol, Front_nrows, Front_ncols, Front_parent, Front_cols, &nfr, InFront, Cmember) ; CCOLAMD_report (stats) ; OK (check_constraints (Cp, Cmember, nrow)) ; /* ---------------------------------------------------------------------- */ /* with a small dense-row threshold */ /* ---------------------------------------------------------------------- */ knobs2 [CCOLAMD_DENSE_ROW] = 0 ; ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; CCOLAMD_report (stats) ; knobs2 [CCOLAMD_DENSE_ROW] = 0.625 ; knobs2 [CCOLAMD_DENSE_COL] = 0 ; ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; CCOLAMD_report (stats) ; knobs2 [CCOLAMD_DENSE_ROW] = 0.625 ; knobs2 [CCOLAMD_DENSE_COL] = -1 ; ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; CCOLAMD_report (stats) ; knobs2 [CCOLAMD_DENSE_COL] = 0 ; /* ---------------------------------------------------------------------- */ /* duplicate entries */ /* ---------------------------------------------------------------------- */ if (ncol > 2 && nrow > 2) { ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; if (Cp [1] - Cp [0] > 2) { Ci [0] = Ci [1] ; } ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; CCOLAMD_report (stats) ; OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "ccolamd perm", cm)) ; } /* ---------------------------------------------------------------------- */ /* csymamd */ /* ---------------------------------------------------------------------- */ if (nrow == ncol) { Int n = nrow ; ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; OK (ok) ; OK (check_constraints (P, Cmember, n)) ; CSYMAMD_report (stats) ; /* ------------------------------------------------------------------ */ /* csymamd errors */ /* ------------------------------------------------------------------ */ ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, NULL, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); ok = CSYMAMD_MAIN (n, NULL, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); CSYMAMD_report (stats) ; ok = CSYMAMD_MAIN (n, Si, NULL, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); CSYMAMD_report (stats) ; ok = CSYMAMD_MAIN (-1, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); CSYMAMD_report (stats) ; p = Sp [n] ; Sp [n] = -1 ; ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); CSYMAMD_report (stats) ; Sp [n] = p ; Sp [0] = -1 ; ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); CSYMAMD_report (stats) ; Sp [0] = 0 ; if (n > 2 && Sp [n] > 3) { p = Sp [1] ; Sp [1] = -1 ; ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); CSYMAMD_report (stats) ; Sp [1] = p ; i = Si [0] ; Si [0] = -1 ; ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT (ok); CSYMAMD_report (stats) ; Si [0] = i ; /* ok, but jumbled */ i = Si [0] ; Si [0] = Si [1] ; Si [1] = i ; ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; OK (ok); CSYMAMD_report (stats) ; i = Si [0] ; Si [0] = Si [1] ; Si [1] = i ; test_memory_handler ( ) ; ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, cm->calloc_memory, cm->free_memory, Cmember, A->stype) ; NOT(ok); CSYMAMD_report (stats) ; normal_memory_handler ( ) ; } } /* ---------------------------------------------------------------------- */ /* error tests */ /* ---------------------------------------------------------------------- */ ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; ok = CCOLAMD_MAIN (ncol, nrow, 0, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; CCOLAMD_report (stats) ; ok = CCOLAMD_MAIN (ncol, nrow, alen, NULL, Cp, knobs, stats, Cmember); NOT (ok) ; CCOLAMD_report (stats) ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, NULL, knobs, stats, Cmember); NOT (ok) ; CCOLAMD_report (stats) ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, NULL, Cmember) ; NOT (ok) ; CCOLAMD_report (stats) ; ok = CCOLAMD_MAIN (-1, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; CCOLAMD_report (stats) ; ok = CCOLAMD_MAIN (ncol, -1, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; CCOLAMD_report (stats) ; ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; Cp [nrow] = -1 ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; CCOLAMD_report (stats) ; Cp [0] = 1 ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; CCOLAMD_report (stats) ; ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; if (nrow > 0 && alen > 0 && Cp [1] > 0) { c = Cmember [0] ; Cmember [0] = -1 ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ;NOT(ok); CCOLAMD_report (stats) ; Cmember [0] = c ; p = Cp [1] ; Cp [1] = -1 ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ;NOT(ok); CCOLAMD_report (stats) ; Cp [1] = p ; i = Ci [0] ; Ci [0] = -1 ; ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ;NOT(ok); CCOLAMD_report (stats) ; Ci [0] = i ; } s = CCOLAMD_recommended (-1, 0, 0) ; OK (s == 0) ; /* ---------------------------------------------------------------------- */ /* free workspace */ /* ---------------------------------------------------------------------- */ CHOLMOD(free) (nrow+1, sizeof (Int), Front_npivcol, cm) ; CHOLMOD(free) (nrow+1, sizeof (Int), Front_nrows, cm) ; CHOLMOD(free) (nrow+1, sizeof (Int), Front_ncols, cm) ; CHOLMOD(free) (nrow+1, sizeof (Int), Front_parent, cm) ; CHOLMOD(free) (nrow+1, sizeof (Int), Front_cols, cm) ; CHOLMOD(free) (nrow+1, sizeof (Int), P, cm) ; CHOLMOD(free) (nrow, sizeof (Int), Cmember, cm) ; CHOLMOD(free) (ncol, sizeof (Int), InFront, cm) ; CHOLMOD(free_sparse) (&S, cm) ; CHOLMOD(free_sparse) (&A2, cm) ; CHOLMOD(free_sparse) (&C, cm) ; cm->print = 1 ; }
int CHOLMOD(row_lsubtree) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ Int *Fi, size_t fnz, /* nonzero pattern of kth row of A', not required * for the symmetric case. Need not be sorted. */ size_t krow, /* row k of L */ cholmod_factor *L, /* the factor L from which parent(i) is derived */ /* ---- output --- */ cholmod_sparse *R, /* pattern of L(k,:), 1-by-n with R->nzmax >= n */ /* --------------- */ cholmod_common *Common ) { Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Lp, *Li, *Lnz ; Int p, pend, parent, t, stype, nrow, k, pf, packed, sorted, top, len, i, mark ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (R, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; stype = A->stype ; if (stype == 0) { RETURN_IF_NULL (Fi, FALSE) ; } if (krow >= A->nrow) { ERROR (CHOLMOD_INVALID, "lsubtree: k invalid") ; return (FALSE) ; } if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax) { ERROR (CHOLMOD_INVALID, "lsubtree: R invalid") ; return (FALSE) ; } if (L->is_super) { ERROR (CHOLMOD_INVALID, "lsubtree: L invalid (cannot be supernodal)") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if (stype < 0) { /* symmetric lower triangular form not supported */ ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; return (FALSE) ; } Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; sorted = A->sorted ; k = krow ; Stack = R->i ; Lp = L->p ; Li = L->i ; Lnz = L->nz ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Flag = Common->Flag ; /* size nrow, Flag [i] < mark must hold */ mark = CHOLMOD(clear_flag) (Common) ; /* ---------------------------------------------------------------------- */ /* compute the pattern of L(k,:) */ /* ---------------------------------------------------------------------- */ top = nrow ; /* Stack is empty */ Flag [k] = mark ; /* do not include diagonal entry in Stack */ #define SCATTER /* do not scatter numerical values */ #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY if (stype != 0) { /* scatter kth col of triu (A), get pattern L(k,:) */ p = Ap [k] ; pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; SUBTREE ; } else { /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ for (pf = 0 ; pf < (Int) fnz ; pf++) { /* get nonzero entry F (t,k) */ t = Fi [pf] ; p = Ap [t] ; pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; SUBTREE ; } } #undef SCATTER #undef PARENT /* shift the stack upwards, to the first part of R */ len = nrow - top ; for (i = 0 ; i < len ; i++) { Stack [i] = Stack [top + i] ; } Rp = R->p ; Rp [0] = 0 ; Rp [1] = len ; R->sorted = FALSE ; CHOLMOD(clear_flag) (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; return (TRUE) ; }
int CHOLMOD(super_numeric) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* F = A' or A(:,f)' */ double beta [2], /* beta*I is added to diagonal of matrix to factorize */ /* ---- in/out --- */ cholmod_factor *L, /* factorization */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *C ; Int *Super, *Map, *SuperMap ; size_t maxcsize ; Int nsuper, n, i, k, s, stype, nrow ; int ok = TRUE, symbolic ; size_t t, w ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_COMPLEX, FALSE) ; stype = A->stype ; if (stype < 0) { if (A->nrow != A->ncol || A->nrow != L->n) { ERROR (CHOLMOD_INVALID, "invalid dimensions") ; return (FALSE) ; } } else if (stype == 0) { if (A->nrow != L->n) { ERROR (CHOLMOD_INVALID, "invalid dimensions") ; return (FALSE) ; } RETURN_IF_NULL (F, FALSE) ; RETURN_IF_XTYPE_INVALID (F, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; if (A->nrow != F->ncol || A->ncol != F->nrow || F->stype != 0) { ERROR (CHOLMOD_INVALID, "F invalid") ; return (FALSE) ; } if (A->xtype != F->xtype) { ERROR (CHOLMOD_INVALID, "A and F must have same xtype") ; return (FALSE) ; } } else { /* symmetric upper case not suppored */ ERROR (CHOLMOD_INVALID, "symmetric upper case not supported") ; return (FALSE) ; } if (!(L->is_super)) { ERROR (CHOLMOD_INVALID, "L not supernodal") ; return (FALSE) ; } if (L->xtype != CHOLMOD_PATTERN) { if (! ((A->xtype == CHOLMOD_REAL && L->xtype == CHOLMOD_REAL) || (A->xtype == CHOLMOD_COMPLEX && L->xtype == CHOLMOD_COMPLEX) || (A->xtype == CHOLMOD_ZOMPLEX && L->xtype == CHOLMOD_COMPLEX))) { ERROR (CHOLMOD_INVALID, "complex type mismatch") ; return (FALSE) ; } } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace in Common */ /* ---------------------------------------------------------------------- */ nsuper = L->nsuper ; maxcsize = L->maxcsize ; nrow = A->nrow ; n = nrow ; PRINT1 (("nsuper "ID" maxcsize %g\n", nsuper, (double) maxcsize)) ; ASSERT (nsuper >= 0 && maxcsize > 0) ; /* w = 2*n + 4*nsuper */ w = CHOLMOD(mult_size_t) (n, 2, &ok) ; t = CHOLMOD(mult_size_t) (nsuper, 4, &ok) ; w = CHOLMOD(add_size_t) (w, t, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (n, w, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get the current factor L and allocate numerical part, if needed */ /* ---------------------------------------------------------------------- */ Super = L->super ; symbolic = (L->xtype == CHOLMOD_PATTERN) ; if (symbolic) { /* convert to supernodal numeric by allocating L->x */ CHOLMOD(change_factor) ( (A->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX, TRUE, TRUE, TRUE, TRUE, L, Common) ; if (Common->status < CHOLMOD_OK) { /* the factor L remains in symbolic supernodal form */ return (FALSE) ; } } ASSERT (L->dtype == DTYPE) ; ASSERT (L->xtype == CHOLMOD_REAL || L->xtype == CHOLMOD_COMPLEX) ; /* supernodal LDL' is not supported */ L->is_ll = TRUE ; /* ---------------------------------------------------------------------- */ /* get more workspace */ /* ---------------------------------------------------------------------- */ C = CHOLMOD(allocate_dense) (maxcsize, 1, maxcsize, L->xtype, Common) ; if (Common->status < CHOLMOD_OK) { int status = Common->status ; if (symbolic) { /* Change L back to symbolic, since the numeric values are not * initialized. This cannot fail. */ CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, Common) ; } /* the factor L is now back to the form it had on input */ Common->status = status ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ SuperMap = Common->Iwork ; /* size n (i/i/l) */ Map = Common->Flag ; /* size n, use Flag as workspace for Map array */ for (i = 0 ; i < n ; i++) { Map [i] = EMPTY ; } /* ---------------------------------------------------------------------- */ /* find the mapping of nodes to relaxed supernodes */ /* ---------------------------------------------------------------------- */ /* SuperMap [k] = s if column k is contained in supernode s */ for (s = 0 ; s < nsuper ; s++) { PRINT1 (("Super ["ID"] "ID" ncols "ID"\n", s, Super[s], Super[s+1]-Super[s])); for (k = Super [s] ; k < Super [s+1] ; k++) { SuperMap [k] = s ; PRINT2 (("relaxed SuperMap ["ID"] = "ID"\n", k, SuperMap [k])) ; } } /* ---------------------------------------------------------------------- */ /* supernodal numerical factorization, using template routine */ /* ---------------------------------------------------------------------- */ switch (A->xtype) { case CHOLMOD_REAL: ok = r_cholmod_super_numeric (A, F, beta, L, C, Common) ; break ; case CHOLMOD_COMPLEX: ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ; break ; case CHOLMOD_ZOMPLEX: /* This operates on complex L, not zomplex */ ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ; break ; } /* ---------------------------------------------------------------------- */ /* clear Common workspace, free temp workspace C, and return */ /* ---------------------------------------------------------------------- */ /* Flag array was used as workspace, clear it */ Common->mark = EMPTY ; /* CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; CHOLMOD(free_dense) (&C, Common) ; return (ok) ; }
cholmod_sparse *CHOLMOD(copy_sparse) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Cx, *Az, *Cz ; Int *Ap, *Ai, *Anz, *Cp, *Ci, *Cnz ; cholmod_sparse *C ; Int p, pend, j, ncol, packed, nzmax, nz, xtype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; if (A->stype != 0 && A->nrow != A->ncol) { ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ; return (NULL) ; } Common->status = CHOLMOD_OK ; ASSERT (CHOLMOD(dump_sparse) (A, "A original", Common) >= 0) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ncol = A->ncol ; nzmax = A->nzmax ; packed = A->packed ; Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; Anz = A->nz ; xtype = A->xtype ; /* ---------------------------------------------------------------------- */ /* allocate the copy */ /* ---------------------------------------------------------------------- */ C = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, A->nzmax, A->sorted, A->packed, A->stype, A->xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } Cp = C->p ; Ci = C->i ; Cx = C->x ; Cz = C->z ; Cnz = C->nz ; /* ---------------------------------------------------------------------- */ /* copy the matrix */ /* ---------------------------------------------------------------------- */ for (j = 0 ; j <= ncol ; j++) { Cp [j] = Ap [j] ; } if (packed) { nz = Ap [ncol] ; for (p = 0 ; p < nz ; p++) { Ci [p] = Ai [p] ; } switch (xtype) { case CHOLMOD_REAL: for (p = 0 ; p < nz ; p++) { Cx [p] = Ax [p] ; } break ; case CHOLMOD_COMPLEX: for (p = 0 ; p < 2*nz ; p++) { Cx [p] = Ax [p] ; } break ; case CHOLMOD_ZOMPLEX: for (p = 0 ; p < nz ; p++) { Cx [p] = Ax [p] ; Cz [p] = Az [p] ; } break ; } } else { for (j = 0 ; j < ncol ; j++) { Cnz [j] = Anz [j] ; } switch (xtype) { case CHOLMOD_PATTERN: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; } } break ; case CHOLMOD_REAL: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; Cx [p] = Ax [p] ; } } break ; case CHOLMOD_COMPLEX: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; Cx [2*p ] = Ax [2*p ] ; Cx [2*p+1] = Ax [2*p+1] ; } } break ; case CHOLMOD_ZOMPLEX: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; Cx [p] = Ax [p] ; Cz [p] = Az [p] ; } } break ; } } /* ---------------------------------------------------------------------- */ /* return the result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_sparse) (C, "C copy", Common) >= 0) ; return (C) ; }
cholmod_triplet *CHOLMOD(read_triplet) ( /* ---- input ---- */ FILE *f, /* file to read from, assumed to already be open */ /* --------------- */ cholmod_common *Common ) { double x, z ; double *Tx ; Int *Ti, *Tj, *Rdeg, *Cdeg ; cholmod_triplet *T ; long l1, l2 ; Int nitems, nrow, ncol, nnz, stype, xtype, unknown, k, nshould, is_lower, is_upper, one_based, i, j, imax, jmax, ignore, skew_symmetric, extra, p ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* read the header line */ /* ---------------------------------------------------------------------- */ stype = 999 ; nitems = get_line (f, &l1, &l2, &x, &z, &stype) ; nrow = l1 ; ncol = l2 ; nnz = x ; if (nrow != ncol) { stype = 0 ; } else if (nitems == 4) { /* first line contains: m n nnz stype */ if (z < 0) { stype = -1 ; } else if (z > 0) { stype = 1 ; } else { stype = 0 ; } } unknown = (stype == 999) ; if (nnz < 0 || nrow < 0 || ncol < 0 || nitems < 3) { /* invalid matrix */ ERROR (CHOLMOD_INVALID, "invalid format") ; return (NULL) ; } if (nrow == 0 || ncol == 0 || nnz == 0) { /* return an empty matrix */ return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, CHOLMOD_REAL, Common)) ; } skew_symmetric = (stype == -2) ; extra = 0 ; if (stype < -1) { /* -2: real or complex skew symmetric converted to unsymmetric */ /* -3: complex symmetric converted to unsymmetric */ stype = 0 ; extra = nnz ; } /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ CHOLMOD(allocate_work) (0, nrow + ncol, 0, Common) ; Rdeg = Common->Iwork ; /* size nrow */ Cdeg = Rdeg + nrow ; /* size ncol */ /* ---------------------------------------------------------------------- */ /* read the nonzero entries */ /* ---------------------------------------------------------------------- */ is_lower = TRUE ; is_upper = TRUE ; one_based = TRUE ; imax = 0 ; jmax = 0 ; Tx = NULL ; Ti = NULL ; Tj = NULL ; xtype = 999 ; nshould = 0 ; for (k = 0 ; k < nnz ; k++) { nitems = get_line (f, &l1, &l2, &x, &z, &ignore) ; i = l1 ; j = l2 ; /* ------------------------------------------------------------------ */ /* for first entry: determine type and allocate triplet matrix */ /* ------------------------------------------------------------------ */ if (k == 0) { if (nitems < 2 || nitems > 4) { /* invalid matrix */ ERROR (CHOLMOD_INVALID, "invalid format") ; return (NULL) ; } else if (nitems == 2) { /* this will be converted into a real matrix later */ xtype = CHOLMOD_PATTERN ; } else if (nitems == 3) { xtype = CHOLMOD_REAL ; } else if (nitems == 4) { xtype = CHOLMOD_COMPLEX ; } /* the rest of the lines should have the same number of entries */ nshould = nitems ; T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz+extra, stype, (xtype == CHOLMOD_PATTERN ? CHOLMOD_REAL : xtype), Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } Ti = T->i ; Tj = T->j ; Tx = T->x ; T->nnz = nnz ; } /* ------------------------------------------------------------------ */ /* save the entry in the triplet matrix */ /* ------------------------------------------------------------------ */ if (nitems != nshould || i < 0 || j < 0) { /* wrong format, premature end-of-file, or negative indices */ CHOLMOD(free_triplet) (&T, Common) ; ERROR (CHOLMOD_INVALID, "invalid matrix file") ; return (NULL) ; } Ti [k] = i ; Tj [k] = j ; if (i < j) { /* this entry is in the upper triangular part */ is_lower = FALSE ; } if (i > j) { /* this entry is in the lower triangular part */ is_upper = FALSE ; } if (xtype == CHOLMOD_REAL) { Tx [k] = x ; } else if (xtype == CHOLMOD_COMPLEX) { Tx [2*k ] = x ; /* real part */ Tx [2*k+1] = z ; /* imaginary part */ } if (i == 0 || j == 0) { one_based = FALSE ; } imax = MAX (i, imax) ; jmax = MAX (j, jmax) ; } /* ---------------------------------------------------------------------- */ /* convert to zero-based */ /* ---------------------------------------------------------------------- */ if (one_based) { /* input matrix is one-based; convert matrix to zero-based */ for (k = 0 ; k < nnz ; k++) { Ti [k]-- ; Tj [k]-- ; } } if (one_based ? (imax > nrow || jmax > ncol):(imax >= nrow || jmax >= ncol)) { /* indices out of range */ CHOLMOD(free_triplet) (&T, Common) ; ERROR (CHOLMOD_INVALID, "indices out of range") ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* add the remainder of skew-symmetric or complex symmetric matrices */ /* ---------------------------------------------------------------------- */ if (extra > 0) { p = nnz ; for (k = 0 ; k < nnz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i != j) { Ti [p] = j ; Tj [p] = i ; if (xtype == CHOLMOD_REAL) { Tx [p] = skew_symmetric ? (-Tx [k]) : (Tx [k]) ; } else if (xtype == CHOLMOD_COMPLEX) { Tx [2*p ] = skew_symmetric ? (-Tx [2*k ]) : (Tx [2*k ]); Tx [2*p+1] = skew_symmetric ? (-Tx [2*k+1]) : (Tx [2*k+1]); } p++ ; } } T->nnz = p ; nnz = p ; } /* ---------------------------------------------------------------------- */ /* determine the stype, if not yet known */ /* ---------------------------------------------------------------------- */ if (unknown) { if (is_lower && is_upper) { /* diagonal matrix, symmetric with upper part present */ stype = 1 ; } else if (is_lower && !is_upper) { /* symmetric, lower triangular part present */ stype = -1 ; } else if (!is_lower && is_upper) { /* symmetric, upper triangular part present */ stype = 1 ; } else { /* unsymmetric */ stype = 0 ; } } T->stype = stype ; /* ---------------------------------------------------------------------- */ /* create values for a pattern-only matrix */ /* ---------------------------------------------------------------------- */ if (xtype == CHOLMOD_PATTERN) { if (stype == 0) { /* unsymmetric case */ for (k = 0 ; k < nnz ; k++) { Tx [k] = 1 ; } } else { /* compute the row and columm degrees (excluding the diagonal) */ for (i = 0 ; i < nrow ; i++) { Rdeg [i] = 0 ; } for (j = 0 ; j < ncol ; j++) { Cdeg [j] = 0 ; } for (k = 0 ; k < nnz ; k++) { i = Ti [k] ; j = Tj [k] ; if ((stype < 0 && i > j) || (stype > 0 && i < j)) { /* both a(i,j) and a(j,i) appear in the matrix */ Rdeg [i]++ ; Cdeg [j]++ ; Rdeg [j]++ ; Cdeg [i]++ ; } } /* assign the numerical values */ for (k = 0 ; k < nnz ; k++) { i = Ti [k] ; j = Tj [k] ; Tx [k] = (i == j) ? (1 + MAX (Rdeg [i], Cdeg [j])) : (-1) ; } } } return (T) ; }
int CHOLMOD(ccolamd) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ Int *Cmember, /* size A->nrow. Cmember [i] = c if row i is in the * constraint set c. c must be >= 0. The # of * constraint sets is max (Cmember) + 1. If Cmember is * NULL, then it is interpretted as Cmember [i] = 0 for * all i */ /* ---- output --- */ Int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *C ; Int ok, nrow, ncol ; size_t alen ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (Perm, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (A->stype != 0) { ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ #ifdef LONG alen = ccolamd_l_recommended (A->nzmax, ncol, nrow) ; #else alen = ccolamd_recommended (A->nzmax, ncol, nrow) ; #endif if (alen == 0) { ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (0, MAX (nrow,ncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, CHOLMOD_PATTERN, Common) ; /* ---------------------------------------------------------------------- */ /* order with ccolamd */ /* ---------------------------------------------------------------------- */ ok = ccolamd_interface (A, alen, Perm, Cmember, fset, fsize, C, Common) ; /* ---------------------------------------------------------------------- */ /* free the workspace and return result */ /* ---------------------------------------------------------------------- */ CHOLMOD(free_sparse) (&C, Common) ; return (ok) ; }
cholmod_sparse *CHOLMOD(copy) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ int stype, /* requested stype of C */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *C ; Int nrow, ncol, up, lo, values, diag, astype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; nrow = A->nrow ; ncol = A->ncol ; if ((stype || A->stype) && nrow != ncol) { /* inputs invalid */ ERROR (CHOLMOD_INVALID, "matrix invalid") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ CHOLMOD(allocate_work) (0, MAX (nrow,ncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ diag = (mode >= 0) ; astype = SIGN (A->stype) ; stype = SIGN (stype) ; up = (astype > 0) ; lo = (astype < 0) ; /* ---------------------------------------------------------------------- */ /* copy the matrix */ /* ---------------------------------------------------------------------- */ if (astype == stype) { /* ------------------------------------------------------------------ */ /* symmetry of A and C are the same */ /* ------------------------------------------------------------------ */ /* copy A into C, keeping the same symmetry. If A is symmetric * entries in the ignored part of A are not copied into C */ C = CHOLMOD(band) (A, -nrow, ncol, mode, Common) ; } else if (!astype) { /* ------------------------------------------------------------------ */ /* convert unsymmetric matrix A into a symmetric matrix C */ /* ------------------------------------------------------------------ */ if (stype > 0) { /* C = triu (A) */ C = CHOLMOD(band) (A, 0, ncol, mode, Common) ; } else { /* C = tril (A) */ C = CHOLMOD(band) (A, -nrow, 0, mode, Common) ; } if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } C->stype = stype ; } else if (astype == -stype) { /* ------------------------------------------------------------------ */ /* transpose a symmetric matrix */ /* ------------------------------------------------------------------ */ /* converting upper to lower or lower to upper */ /* workspace: Iwork (nrow) */ C = CHOLMOD(transpose) (A, values, Common) ; if (!diag) { /* remove diagonal, if requested */ CHOLMOD(band_inplace) (-nrow, ncol, -1, C, Common) ; } } else { /* ------------------------------------------------------------------ */ /* create an unsymmetric copy of a symmetric matrix */ /* ------------------------------------------------------------------ */ C = copy_sym_to_unsym (A, mode, Common) ; } /* ---------------------------------------------------------------------- */ /* return if error */ /* ---------------------------------------------------------------------- */ if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } /* ---------------------------------------------------------------------- */ /* return the result */ /* ---------------------------------------------------------------------- */ DEBUG (diag = CHOLMOD(dump_sparse) (C, "copy", Common)) ; PRINT1 (("mode %d nnzdiag "ID"\n", mode, diag)) ; ASSERT (IMPLIES (mode < 0, diag == 0)) ; return (C) ; }
static cholmod_sparse *copy_sym_to_unsym ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) * -2: pattern only, no diagonal, add 50% + n extra * space to C */ /* --------------- */ cholmod_common *Common ) { double aij ; double *Ax, *Cx ; Int *Ap, *Ai, *Anz, *Cp, *Ci, *Wj, *Iwork ; cholmod_sparse *C ; Int nrow, ncol, nz, packed, j, p, pend, i, pc, up, lo, values, diag, astype, extra ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; Ap = A->p ; Anz = A->nz ; Ai = A->i ; Ax = A->x ; packed = A->packed ; values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ; diag = (mode >= 0) ; astype = SIGN (A->stype) ; up = (astype > 0) ; lo = (astype < 0) ; ASSERT (astype != 0) ; /* ---------------------------------------------------------------------- */ /* create an unsymmetric copy of a symmetric matrix */ /* ---------------------------------------------------------------------- */ Iwork = Common->Iwork ; Wj = Iwork ; /* size ncol (i/i/l) */ /* In MATLAB notation, for converting a symmetric/upper matrix: * U = triu (A) ; * L = tril (U',-1) ; * C = L + U ; * * For converting a symmetric/lower matrix to unsymmetric: * L = tril (A) ; * U = triu (L',1) ; * C = L + U ; */ ASSERT (up || lo) ; PRINT1 (("copy: convert symmetric to unsym\n")) ; /* count the number of entries in each column of C */ for (j = 0 ; j < ncol ; j++) { Wj [j] = 0 ; } for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i == j) { /* the diagonal entry A(i,i) will appear just once * (unless it is excluded with mode < 0) */ if (diag) { Wj [j]++ ; } } else if ((up && i < j) || (lo && i > j)) { /* upper case: A(i,j) is in the strictly upper part; * A(j,i) will be added to the strictly lower part of C. * lower case is the opposite. */ Wj [j]++ ; Wj [i]++ ; } } } nz = 0 ; for (j = 0 ; j < ncol ; j++) { nz += Wj [j] ; } extra = (mode == -2) ? (nz/2 + ncol) : 0 ; /* allocate C. C is sorted if and only if A is sorted */ C = CHOLMOD(allocate_sparse) (nrow, ncol, nz + extra, A->sorted, TRUE, 0, values ? A->xtype : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; } Cp = C->p ; Ci = C->i ; Cx = C->x ; /* construct the column pointers for C */ p = 0 ; for (j = 0 ; j < ncol ; j++) { Cp [j] = p ; p += Wj [j] ; } Cp [ncol] = p ; for (j = 0 ; j < ncol ; j++) { Wj [j] = Cp [j] ; } /* construct C */ if (values) { /* pattern and values */ ASSERT (diag) ; for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; aij = Ax [p] ; if (i == j) { /* add diagonal entry A(i,i) to column i */ pc = Wj [i]++ ; Ci [pc] = i ; Cx [pc] = aij ; } else if ((up && i < j) || (lo && i > j)) { /* add A(i,j) to column j */ pc = Wj [j]++ ; Ci [pc] = i ; Cx [pc] = aij ; /* add A(j,i) to column i */ pc = Wj [i]++ ; Ci [pc] = j ; Cx [pc] = aij ; } } } } else { /* pattern only, possibly excluding the diagonal */ for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i == j) { /* add diagonal entry A(i,i) to column i * (unless it is excluded with mode < 0) */ if (diag) { Ci [Wj [i]++] = i ; } } else if ((up && i < j) || (lo && i > j)) { /* add A(i,j) to column j */ Ci [Wj [j]++] = i ; /* add A(j,i) to column i */ Ci [Wj [i]++] = j ; } } } } /* ---------------------------------------------------------------------- */ /* return the result */ /* ---------------------------------------------------------------------- */ DEBUG (i = CHOLMOD(dump_sparse) (C, "copy_sym_to_unsym", Common)) ; PRINT1 (("mode %d nnzdiag "ID"\n", mode, i)) ; ASSERT (IMPLIES (mode < 0, i == 0)) ; return (C) ; }
void *CHOLMOD(realloc) /* returns pointer to reallocated block */ ( /* ---- input ---- */ size_t nnew, /* requested # of items in reallocated block */ size_t size, /* size of each item */ /* ---- in/out --- */ void *p, /* block of memory to realloc */ size_t *n, /* current size on input, nnew on output if successful*/ /* --------------- */ cholmod_common *Common ) { size_t nold = (*n) ; void *pnew ; size_t s ; int ok = TRUE ; RETURN_IF_NULL_COMMON (NULL) ; if (size == 0) { ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ; p = NULL ; } else if (p == NULL) { /* A fresh object is being allocated. */ PRINT1 (("realloc fresh: %d %d\n", nnew, size)) ; p = CHOLMOD(malloc) (nnew, size, Common) ; *n = (p == NULL) ? 0 : nnew ; } else if (nold == nnew) { /* Nothing to do. Do not change p or n. */ PRINT1 (("realloc nothing: %d %d\n", nnew, size)) ; } else if (nnew >= (Size_max / size) || nnew >= Int_MAX) { /* failure: nnew is too big. Do not change p or n. */ ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; } else { /* The object exists, and is changing to some other nonzero size. */ /* call realloc, or its equivalent */ PRINT1 (("realloc : %d to %d, %d\n", nold, nnew, size)) ; pnew = NULL ; s = CHOLMOD(mult_size_t) (MAX (1,nnew), size, &ok) ; pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ; if (pnew == NULL) { /* Do not change p, since it still points to allocated memory */ if (nnew <= nold) { /* The attempt to reduce the size of the block from n to * nnew has failed. The current block is not modified, so * pretend to succeed, but do not change p. Do change * CHOLMOD's notion of the size of the block, however. */ *n = nnew ; PRINTM (("nnew <= nold failed, pretend to succeed\n")) ; PRINTM (("cholmod_free %p %g cnt: %g inuse %g\n" "cholmod_malloc %p %g cnt: %g inuse %g\n", p, (double) nold*size, (double) Common->malloc_count-1, (double) (Common->memory_inuse - nold*size), p, (double) nnew*size, (double) Common->malloc_count, (double) (Common->memory_inuse + (nnew-nold)*size))) ; Common->memory_inuse += ((nnew-nold) * size) ; } else { /* Increasing the size of the block has failed. * Do not change n. */ ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; } } else { /* success: return revised p and change the size of the block */ PRINTM (("cholmod_free %p %g cnt: %g inuse %g\n" "cholmod_malloc %p %g cnt: %g inuse %g\n", p, (double) nold*size, (double) Common->malloc_count-1, (double) (Common->memory_inuse - nold*size), pnew, (double) nnew*size, (double) Common->malloc_count, (double) (Common->memory_inuse + (nnew-nold)*size))) ; p = pnew ; *n = nnew ; Common->memory_inuse += ((nnew-nold) * size) ; } Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse); } return (p) ; }
int CHOLMOD(realloc_multiple) ( /* ---- input ---- */ size_t nnew, /* requested # of items in reallocated blocks */ int nint, /* number of int/SuiteSparse_long blocks */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* ---- in/out --- */ void **Iblock, /* int or SuiteSparse_long block */ void **Jblock, /* int or SuiteSparse_long block */ void **Xblock, /* complex or double block */ void **Zblock, /* zomplex case only: double block */ size_t *nold_p, /* current size of the I,J,X,Z blocks on input, * nnew on output if successful */ /* --------------- */ cholmod_common *Common ) { double *xx, *zz ; size_t i, j, x, z, nold ; RETURN_IF_NULL_COMMON (FALSE) ; if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "invalid xtype") ; return (FALSE) ; } nold = *nold_p ; if (nint < 1 && xtype == CHOLMOD_PATTERN) { /* nothing to do */ return (TRUE) ; } i = nold ; j = nold ; x = nold ; z = nold ; if (nint > 0) { *Iblock = CHOLMOD(realloc) (nnew, sizeof (Int), *Iblock, &i, Common) ; } if (nint > 1) { *Jblock = CHOLMOD(realloc) (nnew, sizeof (Int), *Jblock, &j, Common) ; } switch (xtype) { case CHOLMOD_REAL: *Xblock = CHOLMOD(realloc) (nnew, sizeof (double), *Xblock, &x, Common) ; break ; case CHOLMOD_COMPLEX: *Xblock = CHOLMOD(realloc) (nnew, 2*sizeof (double), *Xblock, &x, Common) ; break ; case CHOLMOD_ZOMPLEX: *Xblock = CHOLMOD(realloc) (nnew, sizeof (double), *Xblock, &x, Common) ; *Zblock = CHOLMOD(realloc) (nnew, sizeof (double), *Zblock, &z, Common) ; break ; } if (Common->status < CHOLMOD_OK) { /* one or more realloc's failed. Resize all back down to nold. */ if (nold == 0) { if (nint > 0) { *Iblock = CHOLMOD(free) (i, sizeof (Int), *Iblock, Common) ; } if (nint > 1) { *Jblock = CHOLMOD(free) (j, sizeof (Int), *Jblock, Common) ; } switch (xtype) { case CHOLMOD_REAL: *Xblock = CHOLMOD(free) (x, sizeof (double), *Xblock, Common) ; break ; case CHOLMOD_COMPLEX: *Xblock = CHOLMOD(free) (x, 2*sizeof (double), *Xblock, Common) ; break ; case CHOLMOD_ZOMPLEX: *Xblock = CHOLMOD(free) (x, sizeof (double), *Xblock, Common) ; *Zblock = CHOLMOD(free) (x, sizeof (double), *Zblock, Common) ; break ; } } else { if (nint > 0) { *Iblock = CHOLMOD(realloc) (nold, sizeof (Int), *Iblock, &i, Common) ; } if (nint > 1) { *Jblock = CHOLMOD(realloc) (nold, sizeof (Int), *Jblock, &j, Common) ; } switch (xtype) { case CHOLMOD_REAL: *Xblock = CHOLMOD(realloc) (nold, sizeof (double), *Xblock, &x, Common) ; break ; case CHOLMOD_COMPLEX: *Xblock = CHOLMOD(realloc) (nold, 2*sizeof (double), *Xblock, &x, Common) ; break ; case CHOLMOD_ZOMPLEX: *Xblock = CHOLMOD(realloc) (nold, sizeof (double), *Xblock, &x, Common) ; *Zblock = CHOLMOD(realloc) (nold, sizeof (double), *Zblock, &z, Common) ; break ; } } return (FALSE) ; } if (nold == 0) { /* New space was allocated. Clear the first entry so that valgrind * doesn't complain about its access in change_complexity * (Core/cholmod_complex.c). */ xx = *Xblock ; zz = *Zblock ; switch (xtype) { case CHOLMOD_REAL: xx [0] = 0 ; break ; case CHOLMOD_COMPLEX: xx [0] = 0 ; xx [1] = 0 ; break ; case CHOLMOD_ZOMPLEX: xx [0] = 0 ; zz [0] = 0 ; break ; } } /* all realloc's succeeded, change size to reflect realloc'ed size. */ *nold_p = nnew ; return (TRUE) ; }
cholmod_factor *CHOLMOD(allocate_factor) ( /* ---- input ---- */ size_t n, /* L is n-by-n */ /* --------------- */ cholmod_common *Common ) { Int j ; Int *Perm, *ColCount ; cholmod_factor *L ; int ok = TRUE ; RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; /* ensure the dimension does not cause integer overflow */ (void) CHOLMOD(add_size_t) (n, 2, &ok) ; if (!ok || n > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } L = CHOLMOD(malloc) (sizeof (cholmod_factor), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } L->n = n ; L->is_ll = FALSE ; L->is_super = FALSE ; L->is_monotonic = TRUE ; L->itype = ITYPE ; L->xtype = CHOLMOD_PATTERN ; L->dtype = DTYPE ; /* allocate the purely symbolic part of L */ L->ordering = CHOLMOD_NATURAL ; L->Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ; L->ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ; /* simplicial part of L is empty */ L->nzmax = 0 ; L->p = NULL ; L->i = NULL ; L->x = NULL ; L->z = NULL ; L->nz = NULL ; L->next = NULL ; L->prev = NULL ; /* supernodal part of L is also empty */ L->nsuper = 0 ; L->ssize = 0 ; L->xsize = 0 ; L->maxesize = 0 ; L->maxcsize = 0 ; L->super = NULL ; L->pi = NULL ; L->px = NULL ; L->s = NULL ; /* L has not been factorized */ L->minor = n ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_factor) (&L, Common) ; return (NULL) ; /* out of memory */ } /* initialize Perm and ColCount */ Perm = L->Perm ; for (j = 0 ; j < ((Int) n) ; j++) { Perm [j] = j ; } ColCount = L->ColCount ; for (j = 0 ; j < ((Int) n) ; j++) { ColCount [j] = 1 ; } return (L) ; }
cholmod_factor *CHOLMOD(copy_factor) ( /* ---- input ---- */ cholmod_factor *L, /* factor to copy */ /* --------------- */ cholmod_common *Common ) { cholmod_factor *L2 ; double *Lx, *L2x, *Lz, *L2z ; Int *Perm, *ColCount, *Lp, *Li, *Lnz, *Lnext, *Lprev, *Lsuper, *Lpi, *Lpx, *Ls, *Perm2, *ColCount2, *L2p, *L2i, *L2nz, *L2next, *L2prev, *L2super, *L2pi, *L2px, *L2s ; Int n, j, p, pend, s, xsize, ssize, nsuper ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (L, NULL) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start copy", Common)) ; n = L->n ; /* ---------------------------------------------------------------------- */ /* allocate a simplicial symbolic factor */ /* ---------------------------------------------------------------------- */ /* allocates L2->Perm and L2->ColCount */ L2 = CHOLMOD(allocate_factor) (n, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } ASSERT (L2->xtype == CHOLMOD_PATTERN && !(L2->is_super)) ; Perm = L->Perm ; ColCount = L->ColCount ; Perm2 = L2->Perm ; ColCount2 = L2->ColCount ; L2->ordering = L->ordering ; for (j = 0 ; j < n ; j++) { Perm2 [j] = Perm [j] ; } for (j = 0 ; j < n ; j++) { ColCount2 [j] = ColCount [j] ; } L2->is_ll = L->is_ll ; /* ---------------------------------------------------------------------- */ /* copy the rest of the factor */ /* ---------------------------------------------------------------------- */ if (L->xtype != CHOLMOD_PATTERN && !(L->super)) { /* ------------------------------------------------------------------ */ /* allocate a simplicial numeric factor */ /* ------------------------------------------------------------------ */ /* allocate L2->p, L2->nz, L2->prev, L2->next, L2->i, and L2->x. * packed = -1 so that cholmod_change_factor allocates space of * size L2->nzmax */ L2->nzmax = L->nzmax ; if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, -1, TRUE, L2, Common)) { CHOLMOD(free_factor) (&L2, Common) ; return (NULL) ; /* out of memory */ } ASSERT (MAX (1, L->nzmax) == L2->nzmax) ; /* ------------------------------------------------------------------ */ /* copy the contents of a simplicial numeric factor */ /* ------------------------------------------------------------------ */ Lp = L->p ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lnz = L->nz ; Lnext = L->next ; Lprev = L->prev ; L2p = L2->p ; L2i = L2->i ; L2x = L2->x ; L2z = L2->z ; L2nz = L2->nz ; L2next = L2->next ; L2prev = L2->prev ; L2->xtype = L->xtype ; L2->dtype = L->dtype ; for (j = 0 ; j <= n ; j++) { L2p [j] = Lp [j] ; } for (j = 0 ; j < n+2 ; j++) { L2prev [j] = Lprev [j] ; } for (j = 0 ; j < n+2 ; j++) { L2next [j] = Lnext [j] ; } for (j = 0 ; j < n ; j++) { L2nz [j] = Lnz [j] ; } for (j = 0 ; j < n ; j++) { p = Lp [j] ; pend = p + Lnz [j] ; for ( ; p < pend ; p++) { L2i [p] = Li [p] ; } p = Lp [j] ; if (L->xtype == CHOLMOD_REAL) { for ( ; p < pend ; p++) { L2x [p] = Lx [p] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for ( ; p < pend ; p++) { L2x [2*p ] = Lx [2*p ] ; L2x [2*p+1] = Lx [2*p+1] ; } } else if (L->xtype == CHOLMOD_ZOMPLEX) { for ( ; p < pend ; p++) { L2x [p] = Lx [p] ; L2z [p] = Lz [p] ; } } } } else if (L->is_super) { /* ------------------------------------------------------------------ */ /* copy a supernodal factor */ /* ------------------------------------------------------------------ */ xsize = L->xsize ; ssize = L->ssize ; nsuper = L->nsuper ; L2->xsize = xsize ; L2->ssize = ssize ; L2->nsuper = nsuper ; /* allocate L2->super, L2->pi, L2->px, and L2->s. Allocate L2->x if * L is numeric */ if (!CHOLMOD(change_factor) (L->xtype, TRUE, TRUE, TRUE, TRUE, L2, Common)) { CHOLMOD(free_factor) (&L2, Common) ; return (NULL) ; /* out of memory */ } ASSERT (L2->s != NULL) ; /* ------------------------------------------------------------------ */ /* copy the contents of a supernodal factor */ /* ------------------------------------------------------------------ */ Lsuper = L->super ; Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; Lx = L->x ; L2super = L2->super ; L2pi = L2->pi ; L2px = L2->px ; L2s = L2->s ; L2x = L2->x ; L2->maxcsize = L->maxcsize ; L2->maxesize = L->maxesize ; for (s = 0 ; s <= nsuper ; s++) { L2super [s] = Lsuper [s] ; } for (s = 0 ; s <= nsuper ; s++) { L2pi [s] = Lpi [s] ; } for (s = 0 ; s <= nsuper ; s++) { L2px [s] = Lpx [s] ; } L2s [0] = 0 ; for (p = 0 ; p < ssize ; p++) { L2s [p] = Ls [p] ; } if (L->xtype == CHOLMOD_REAL) { for (p = 0 ; p < xsize ; p++) { L2x [p] = Lx [p] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for (p = 0 ; p < 2*xsize ; p++) { L2x [p] = Lx [p] ; } } } L2->minor = L->minor ; L2->is_monotonic = L->is_monotonic ; DEBUG (CHOLMOD(dump_factor) (L2, "L2 got copied", Common)) ; ASSERT (L2->xtype == L->xtype && L2->is_super == L->is_super) ; return (L2) ; }
cholmod_sparse *CHOLMOD(factor_to_sparse) ( /* ---- in/out --- */ cholmod_factor *L, /* factor to copy, converted to symbolic on output */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *Lsparse ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (L, NULL) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start convert to matrix", Common)) ; /* ---------------------------------------------------------------------- */ /* convert to packed, monotonic, simplicial, numeric */ /* ---------------------------------------------------------------------- */ /* leave as LL or LDL' */ if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, TRUE, TRUE, L, Common)) { ERROR (CHOLMOD_INVALID, "cannot convert L") ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* create Lsparse */ /* ---------------------------------------------------------------------- */ /* allocate the header for Lsparse, the sparse matrix version of L */ Lsparse = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* transfer the contents from L to Lsparse */ Lsparse->nrow = L->n ; Lsparse->ncol = L->n ; Lsparse->p = L->p ; Lsparse->i = L->i ; Lsparse->x = L->x ; Lsparse->z = L->z ; Lsparse->nz = NULL ; Lsparse->stype = 0 ; Lsparse->itype = L->itype ; Lsparse->xtype = L->xtype ; Lsparse->dtype = L->dtype ; Lsparse->sorted = TRUE ; Lsparse->packed = TRUE ; Lsparse->nzmax = L->nzmax ; ASSERT (CHOLMOD(dump_sparse) (Lsparse, "Lsparse", Common) >= 0) ; /* ---------------------------------------------------------------------- */ /* convert L to symbolic, but do not free contents transfered to Lsparse */ /* ---------------------------------------------------------------------- */ L->p = NULL ; L->i = NULL ; L->x = NULL ; L->z = NULL ; L->xtype = CHOLMOD_PATTERN ; CHOLMOD(change_factor) (CHOLMOD_PATTERN, FALSE, FALSE, TRUE, TRUE, L, Common) ; return (Lsparse) ; }
int CHOLMOD(write_sparse) ( /* ---- input ---- */ FILE *f, /* file to write to, must already be open */ cholmod_sparse *A, /* matrix to print */ cholmod_sparse *Z, /* optional matrix with pattern of explicit zeros */ char *comments, /* optional filename of comments to include */ /* --------------- */ cholmod_common *Common ) { double x, z ; double *Ax, *Az ; Int *Ap, *Ai, *Anz, *Zp, *Zi, *Znz ; Int nrow, ncol, is_complex, symmetry, i, j, q, iz, p, nz, is_binary, stype, is_integer, asym, is_sym, xtype, apacked, zpacked, pend, qend, k, zsym ; int ok ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (f, EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; if (Z != NULL && (Z->nrow == 0 || Z->ncol == 0)) { /* Z is non-NULL but empty, so treat it as a NULL matrix */ Z = NULL ; } if (Z != NULL) { RETURN_IF_XTYPE_INVALID (Z, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; if (Z->nrow != A->nrow || Z->ncol != A->ncol || Z->stype != A->stype) { ERROR (CHOLMOD_INVALID, "dimension or type of A and Z mismatch") ; return (EMPTY) ; } } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get the A matrix */ /* ---------------------------------------------------------------------- */ Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; Anz = A->nz ; nrow = A->nrow ; ncol = A->ncol ; xtype = A->xtype ; apacked = A->packed ; if (xtype == CHOLMOD_PATTERN) { /* a CHOLMOD pattern matrix is printed as "pattern" in the file */ is_binary = TRUE ; is_integer = FALSE ; is_complex = FALSE ; } else if (xtype == CHOLMOD_REAL) { /* determine if a real matrix is in fact binary or integer */ is_binary = TRUE ; is_integer = TRUE ; is_complex = FALSE ; for (j = 0 ; (is_binary || is_integer) && j < ncol ; j++) { p = Ap [j] ; pend = (apacked) ? Ap [j+1] : p + Anz [j] ; for ( ; (is_binary || is_integer) && p < pend ; p++) { x = Ax [p] ; if (x != 1) { is_binary = FALSE ; } /* convert to Int and then back to double */ i = (Int) x ; z = (double) i ; if (z != x) { is_integer = FALSE ; } } } } else { /* a CHOLMOD complex matrix is printed as "complex" in the file */ is_binary = FALSE ; is_integer = FALSE ; is_complex = TRUE ; } /* ---------------------------------------------------------------------- */ /* get the Z matrix (only consider the pattern) */ /* ---------------------------------------------------------------------- */ Zp = NULL ; Zi = NULL ; Znz = NULL ; zpacked = TRUE ; if (Z != NULL) { Zp = Z->p ; Zi = Z->i ; Znz = Z->nz ; zpacked = Z->packed ; } /* ---------------------------------------------------------------------- */ /* determine the symmetry of A and Z */ /* ---------------------------------------------------------------------- */ stype = A->stype ; if (A->nrow != A->ncol) { asym = CHOLMOD_MM_RECTANGULAR ; } else if (stype != 0) { /* CHOLMOD's A and Z matrices have a symmetric (and matching) stype. * Note that the diagonal is not checked. */ asym = is_complex ? CHOLMOD_MM_HERMITIAN : CHOLMOD_MM_SYMMETRIC ; } else if (!A->sorted) { /* A is in unsymmetric storage, but unsorted */ asym = CHOLMOD_MM_UNSYMMETRIC ; } else { /* CHOLMOD's stype is zero (stored in unsymmetric form) */ asym = EMPTY ; zsym = EMPTY ; #ifndef NMATRIXOPS /* determine if the matrices are in fact symmetric or Hermitian */ asym = CHOLMOD(symmetry) (A, 1, NULL, NULL, NULL, NULL, Common) ; zsym = (Z == NULL) ? 999 : CHOLMOD(symmetry) (Z, 1, NULL, NULL, NULL, NULL, Common) ; #endif if (asym == EMPTY || zsym <= CHOLMOD_MM_UNSYMMETRIC) { /* not computed, out of memory, or Z is unsymmetric */ asym = CHOLMOD_MM_UNSYMMETRIC ; } } /* ---------------------------------------------------------------------- */ /* write the Matrix Market header */ /* ---------------------------------------------------------------------- */ ok = fprintf (f, "%%%%MatrixMarket matrix coordinate") > 0 ; if (is_complex) { ok = ok && (fprintf (f, " complex") > 0) ; } else if (is_binary) { ok = ok && (fprintf (f, " pattern") > 0) ; } else if (is_integer) { ok = ok && (fprintf (f, " integer") > 0) ; } else { ok = ok && (fprintf (f, " real") > 0) ; } switch (asym) { case CHOLMOD_MM_RECTANGULAR: case CHOLMOD_MM_UNSYMMETRIC: /* A is rectangular or unsymmetric */ ok = ok && (fprintf (f, " general\n") > 0) ; is_sym = FALSE ; symmetry = CHOLMOD_MM_UNSYMMETRIC ; break ; case CHOLMOD_MM_SYMMETRIC: case CHOLMOD_MM_SYMMETRIC_POSDIAG: /* A is symmetric */ ok = ok && (fprintf (f, " symmetric\n") > 0) ; is_sym = TRUE ; symmetry = CHOLMOD_MM_SYMMETRIC ; break ; case CHOLMOD_MM_HERMITIAN: case CHOLMOD_MM_HERMITIAN_POSDIAG: /* A is Hermitian */ ok = ok && (fprintf (f, " Hermitian\n") > 0) ; is_sym = TRUE ; symmetry = CHOLMOD_MM_HERMITIAN ; break ; case CHOLMOD_MM_SKEW_SYMMETRIC: /* A is skew symmetric */ ok = ok && (fprintf (f, " skew-symmetric\n") > 0) ; is_sym = TRUE ; symmetry = CHOLMOD_MM_SKEW_SYMMETRIC ; break ; } /* ---------------------------------------------------------------------- */ /* include the comments if present */ /* ---------------------------------------------------------------------- */ ok = ok && include_comments (f, comments) ; /* ---------------------------------------------------------------------- */ /* write a sparse matrix (A and Z) */ /* ---------------------------------------------------------------------- */ nz = ntriplets (A, is_sym) + ntriplets (Z, is_sym) ; /* write the first data line, with nrow, ncol, and # of triplets */ ok = ok && (fprintf (f, ID " " ID " " ID "\n", nrow, ncol, nz) > 0) ; for (j = 0 ; ok && j < ncol ; j++) { /* merge column of A and Z */ p = Ap [j] ; pend = (apacked) ? Ap [j+1] : p + Anz [j] ; q = (Z == NULL) ? 0 : Zp [j] ; qend = (Z == NULL) ? 0 : ((zpacked) ? Zp [j+1] : q + Znz [j]) ; while (ok) { /* get the next row index from A and Z */ i = (p < pend) ? Ai [p] : (nrow+1) ; iz = (q < qend) ? Zi [q] : (nrow+2) ; if (i <= iz) { /* get A(i,j), or quit if both A and Z are exhausted */ if (i == nrow+1) break ; get_value (Ax, Az, p, xtype, &x, &z) ; p++ ; } else { /* get Z(i,j) */ i = iz ; x = 0 ; z = 0 ; q++ ; } if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym))) { /* CHOLMOD matrix is symmetric-lower (and so is the file); * or CHOLMOD matrix is unsymmetric and either A(i,j) is in * the lower part or the file is unsymmetric. */ ok = ok && print_triplet (f, is_binary, is_complex, is_integer, i,j, x,z) ; } else if (stype > 0 && i <= j) { /* CHOLMOD matrix is symmetric-upper, but the file is * symmetric-lower. Need to transpose the entry. If the * matrix is real, the complex part is ignored. If the matrix * is complex, it Hermitian. */ ASSERT (IMPLIES (is_complex, asym == CHOLMOD_MM_HERMITIAN)) ; if (z != 0) { z = -z ; } ok = ok && print_triplet (f, is_binary, is_complex, is_integer, j,i, x,z) ; } } } if (!ok) { ERROR (CHOLMOD_INVALID, "error reading/writing file") ; return (EMPTY) ; } return (asym) ; }
cholmod_dense *CHOLMOD(allocate_dense) ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ size_t d, /* leading dimension */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *X ; size_t nzmax, nzmax0 ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; if (d < nrow) { ERROR (CHOLMOD_INVALID, "leading dimension invalid") ; return (NULL) ; } if (xtype < CHOLMOD_REAL || xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "xtype invalid") ; return (NULL) ; } /* ensure the dimensions do not cause integer overflow */ (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ; /* nzmax = MAX (1, d*ncol) ; */ nzmax = CHOLMOD(mult_size_t) (d, ncol, &ok) ; nzmax = MAX (1, nzmax) ; if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate header */ /* ---------------------------------------------------------------------- */ X = CHOLMOD(malloc) (sizeof (cholmod_dense), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } PRINT1 (("cholmod_allocate_dense %d-by-%d nzmax %d xtype %d\n", nrow, ncol, nzmax, xtype)) ; X->nrow = nrow ; X->ncol = ncol ; X->nzmax = nzmax ; X->xtype = xtype ; X->dtype = DTYPE ; X->x = NULL ; X->z = NULL ; X->d = d ; /* ---------------------------------------------------------------------- */ /* allocate the matrix itself */ /* ---------------------------------------------------------------------- */ nzmax0 = 0 ; CHOLMOD(realloc_multiple) (nzmax, 0, xtype, NULL, NULL, &(X->x), &(X->z), &nzmax0, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_dense) (&X, Common) ; return (NULL) ; /* out of memory */ } return (X) ; }
int CHOLMOD(csymamd) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ /* ---- output --- */ Int *Cmember, /* size nrow. see cholmod_ccolamd.c for description */ Int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) { double knobs [CCOLAMD_KNOBS] ; Int *perm, *Head ; Int ok, i, nrow, stats [CCOLAMD_STATS] ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (Perm, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; if (A->nrow != A->ncol || !(A->packed)) { ERROR (CHOLMOD_INVALID, "matrix must be square and packed") ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* order the matrix (does not affect A->p or A->i) */ /* ---------------------------------------------------------------------- */ perm = Common->Head ; /* size nrow+1 (i/l/l) */ /* get parameters */ #ifdef LONG amesos_ccolamd_l_set_defaults (knobs) ; #else amesos_ccolamd_set_defaults (knobs) ; #endif if (Common->current >= 0 && Common->current < CHOLMOD_MAXMETHODS) { /* get the knobs from the Common parameters */ knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense ; knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ; } { #ifdef LONG amesos_csymamd_l (nrow, A->i, A->p, perm, knobs, stats, Common->calloc_memory, Common->free_memory, Cmember, A->stype) ; #else amesos_csymamd (nrow, A->i, A->p, perm, knobs, stats, Common->calloc_memory, Common->free_memory, Cmember, A->stype) ; #endif ok = stats [CCOLAMD_STATUS] ; } if (ok == CCOLAMD_ERROR_out_of_memory) { ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; } ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; /* ---------------------------------------------------------------------- */ /* free the workspace and return result */ /* ---------------------------------------------------------------------- */ /* permutation returned in perm [0..n-1] */ for (i = 0 ; i < nrow ; i++) { Perm [i] = perm [i] ; } /* clear Head workspace (used for perm, in csymamd): */ Head = Common->Head ; for (i = 0 ; i <= nrow ; i++) { Head [i] = EMPTY ; } return (ok) ; }
static int permute_matrices ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to permute */ Int ordering, /* ordering method used */ Int *Perm, /* fill-reducing permutation */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ Int do_rowcolcounts,/* if TRUE, compute both S and F. If FALSE, only * S is needed for the symmetric case, and only F for * the unsymmetric case */ /* ---- output --- */ cholmod_sparse **A1_handle, /* see comments below for A1, A2, S, F */ cholmod_sparse **A2_handle, cholmod_sparse **S_handle, cholmod_sparse **F_handle, /* --------------- */ cholmod_common *Common ) { cholmod_sparse *A1, *A2, *S, *F ; *A1_handle = NULL ; *A2_handle = NULL ; *S_handle = NULL ; *F_handle = NULL ; A1 = NULL ; A2 = NULL ; if (ordering == CHOLMOD_NATURAL) { /* ------------------------------------------------------------------ */ /* natural ordering of A */ /* ------------------------------------------------------------------ */ if (A->stype < 0) { /* symmetric lower case: A already in lower form, so S=A' */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ; F = A ; S = A2 ; } else if (A->stype > 0) { /* symmetric upper case: F = pattern of triu (A)', S = A */ /* workspace: Iwork (nrow) */ if (do_rowcolcounts) { /* F not needed for symmetric case if do_rowcolcounts FALSE */ A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; } F = A1 ; S = A ; } else { /* unsymmetric case: F = pattern of A (:,f)', S = A */ /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */ A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; F = A1 ; S = A ; } } else { /* ------------------------------------------------------------------ */ /* A is permuted */ /* ------------------------------------------------------------------ */ if (A->stype < 0) { /* symmetric lower case: S = tril (A (p,p))' and F = S' */ /* workspace: Iwork (2*nrow) */ A2 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; S = A2 ; /* workspace: Iwork (nrow) */ if (do_rowcolcounts) { /* F not needed for symmetric case if do_rowcolcounts FALSE */ A1 = CHOLMOD(ptranspose) (A2, 0, NULL, NULL, 0, Common) ; } F = A1 ; } else if (A->stype > 0) { /* symmetric upper case: F = triu (A (p,p))' and S = F' */ /* workspace: Iwork (2*nrow) */ A1 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; F = A1 ; /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; S = A2 ; } else { /* unsymmetric case: F = A (p,f)' and S = F' */ /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */ A1 = CHOLMOD(ptranspose) (A, 0, Perm, fset, fsize, Common) ; F = A1 ; if (do_rowcolcounts) { /* S not needed for unsymmetric case if do_rowcolcounts FALSE */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; } S = A2 ; } } /* If any cholmod_*transpose fails, one or more matrices will be NULL */ *A1_handle = A1 ; *A2_handle = A2 ; *S_handle = S ; *F_handle = F ; return (Common->status == CHOLMOD_OK) ; }
cholmod_sparse *CHOLMOD(add) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to add */ cholmod_sparse *B, /* matrix to add */ double alpha [2], /* scale factor for A */ double beta [2], /* scale factor for B */ int values, /* if TRUE compute the numerical values of C */ int sorted, /* if TRUE, sort columns of C */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Bx, *Cx, *W ; Int apacked, up, lo, nrow, ncol, bpacked, nzmax, pa, paend, pb, pbend, i, j, p, mark, nz ; Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Flag, *Cp, *Ci ; cholmod_sparse *A2, *B2, *C ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_NULL (B, NULL) ; values = values && (A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; if (A->nrow != B->nrow || A->ncol != B->ncol) { /* A and B must have the same dimensions */ ERROR (CHOLMOD_INVALID, "A and B dimesions do not match") ; return (NULL) ; } /* A and B must have the same numerical type if values is TRUE (both must * be CHOLMOD_REAL, this is implicitly checked above) */ Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; CHOLMOD(allocate_work) (nrow, MAX (nrow,ncol), values ? nrow : 0, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if (nrow <= 1) { /* C will be implicitly sorted, so no need to sort it here */ sorted = FALSE ; } /* convert A or B to unsymmetric, if necessary */ A2 = NULL ; B2 = NULL ; if (A->stype != B->stype) { if (A->stype) { /* workspace: Iwork (max (nrow,ncol)) */ A2 = CHOLMOD(copy) (A, 0, values, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } A = A2 ; } if (B->stype) { /* workspace: Iwork (max (nrow,ncol)) */ B2 = CHOLMOD(copy) (B, 0, values, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&A2, Common) ; return (NULL) ; /* out of memory */ } B = B2 ; } } /* get the A matrix */ ASSERT (A->stype == B->stype) ; up = (A->stype > 0) ; lo = (A->stype < 0) ; Ap = A->p ; Anz = A->nz ; Ai = A->i ; Ax = A->x ; apacked = A->packed ; /* get the B matrix */ Bp = B->p ; Bnz = B->nz ; Bi = B->i ; Bx = B->x ; bpacked = B->packed ; /* get workspace */ W = Common->Xwork ; /* size nrow, used if values is TRUE */ Flag = Common->Flag ; /* size nrow, Flag [0..nrow-1] < mark on input */ /* ---------------------------------------------------------------------- */ /* allocate the result C */ /* ---------------------------------------------------------------------- */ /* If integer overflow occurs, nzmax < 0 and the allocate fails properly * (likewise in most other matrix manipulation routines). */ nzmax = CHOLMOD(nnz) (A, Common) + CHOLMOD(nnz) (B, Common) ; C = CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, FALSE, TRUE, SIGN (A->stype), values ? A->xtype : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; return (NULL) ; /* out of memory */ } Cp = C->p ; Ci = C->i ; Cx = C->x ; /* ---------------------------------------------------------------------- */ /* compute C = alpha*A + beta*B */ /* ---------------------------------------------------------------------- */ nz = 0 ; for (j = 0 ; j < ncol ; j++) { Cp [j] = nz ; /* clear the Flag array */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; /* scatter B into W */ pb = Bp [j] ; pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ; for (p = pb ; p < pbend ; p++) { i = Bi [p] ; if ((up && i > j) || (lo && i < j)) { continue ; } Flag [i] = mark ; if (values) { W [i] = beta [0] * Bx [p] ; } } /* add A and gather from W into C(:,j) */ pa = Ap [j] ; paend = (apacked) ? (Ap [j+1]) : (pa + Anz [j]) ; for (p = pa ; p < paend ; p++) { i = Ai [p] ; if ((up && i > j) || (lo && i < j)) { continue ; } Flag [i] = EMPTY ; Ci [nz] = i ; if (values) { Cx [nz] = W [i] + alpha [0] * Ax [p] ; W [i] = 0 ; } nz++ ; } /* gather remaining entries into C(:,j), using pattern of B */ for (p = pb ; p < pbend ; p++) { i = Bi [p] ; if ((up && i > j) || (lo && i < j)) { continue ; } if (Flag [i] == mark) { Ci [nz] = i ; if (values) { Cx [nz] = W [i] ; W [i] = 0 ; } nz++ ; } } } Cp [ncol] = nz ; /* ---------------------------------------------------------------------- */ /* reduce C in size and free temporary matrices */ /* ---------------------------------------------------------------------- */ ASSERT (MAX (1,nz) <= C->nzmax) ; CHOLMOD(reallocate_sparse) (nz, C, Common) ; ASSERT (Common->status >= CHOLMOD_OK) ; /* clear the Flag array */ mark = CHOLMOD(clear_flag) (Common) ; CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; /* ---------------------------------------------------------------------- */ /* sort C, if requested */ /* ---------------------------------------------------------------------- */ if (sorted) { /* workspace: Iwork (max (nrow,ncol)) */ if (!CHOLMOD(sort) (C, Common)) { CHOLMOD(free_sparse) (&C, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } } } /* ---------------------------------------------------------------------- */ /* return result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_sparse) (C, "add", Common) >= 0) ; return (C) ; }
int CHOLMOD(analyze_ordering) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ int ordering, /* ordering method used */ Int *Perm, /* size n, fill-reducing permutation to analyze */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ Int *Parent, /* size n, elimination tree */ Int *Post, /* size n, postordering of elimination tree */ Int *ColCount, /* size n, nnz in each column of L */ /* ---- workspace */ Int *First, /* size n workspace for cholmod_postorder */ Int *Level, /* size n workspace for cholmod_postorder */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *A1, *A2, *S, *F ; Int n, ok, do_rowcolcounts ; /* check inputs */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; n = A->nrow ; do_rowcolcounts = (ColCount != NULL) ; /* permute A according to Perm and fset */ ok = permute_matrices (A, ordering, Perm, fset, fsize, do_rowcolcounts, &A1, &A2, &S, &F, Common) ; /* find etree of S (symmetric upper/lower case) or F (unsym case) */ /* workspace: symmmetric: Iwork (nrow), unsym: Iwork (nrow+ncol) */ ok = ok && CHOLMOD(etree) (A->stype ? S:F, Parent, Common) ; /* postorder the etree (required by cholmod_rowcolcounts) */ /* workspace: Iwork (2*nrow) */ ok = ok && (CHOLMOD(postorder) (Parent, n, NULL, Post, Common) == n) ; /* cholmod_postorder doesn't set Common->status if it returns < n */ Common->status = (!ok && Common->status == CHOLMOD_OK) ? CHOLMOD_INVALID : Common->status ; /* analyze LL'=S or SS' or S(:,f)*S(:,f)' */ /* workspace: * if symmetric: Flag (nrow), Iwork (2*nrow) * if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1) */ if (do_rowcolcounts) { ok = ok && CHOLMOD(rowcolcounts) (A->stype ? F:S, fset, fsize, Parent, Post, NULL, ColCount, First, Level, Common) ; } /* free temporary matrices and return result */ CHOLMOD(free_sparse) (&A1, Common) ; CHOLMOD(free_sparse) (&A2, Common) ; return (ok) ; }
static int ccolamd_interface ( cholmod_sparse *A, size_t alen, Int *Perm, Int *Cmember, Int *fset, Int fsize, cholmod_sparse *C, cholmod_common *Common ) { double knobs [CCOLAMD_KNOBS] ; Int *Cp = NULL ; Int ok, k, nrow, ncol, stats [CCOLAMD_STATS] ; nrow = A->nrow ; ncol = A->ncol ; /* ---------------------------------------------------------------------- */ /* copy (and transpose) the input matrix A into the ccolamd workspace */ /* ---------------------------------------------------------------------- */ /* C = A (:,f)', which also packs A if needed. */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset non-NULL) */ ok = CHOLMOD(transpose_unsym) (A, 0, NULL, fset, fsize, C, Common) ; /* ---------------------------------------------------------------------- */ /* order the matrix (destroys the contents of C->i and C->p) */ /* ---------------------------------------------------------------------- */ /* get parameters */ #ifdef LONG ccolamd_l_set_defaults (knobs) ; #else ccolamd_set_defaults (knobs) ; #endif if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS) { /* this is the CHOLMOD default, not the CCOLAMD default */ knobs [CCOLAMD_DENSE_ROW] = -1 ; } else { /* get the knobs from the Common parameters */ knobs [CCOLAMD_DENSE_COL] =Common->method[Common->current].prune_dense ; knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense2; knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ; knobs [CCOLAMD_LU] =Common->method[Common->current].order_for_lu; } if (ok) { #ifdef LONG ccolamd_l (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ; #else ccolamd (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ; #endif ok = stats [CCOLAMD_STATUS] ; ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; /* permutation returned in C->p, if the ordering succeeded */ Cp = C->p ; for (k = 0 ; k < nrow ; k++) { Perm [k] = Cp [k] ; } } return (ok) ; }
cholmod_factor *CHOLMOD(analyze_p2) ( /* ---- input ---- */ int for_cholesky, /* if TRUE, then analyze for Cholesky; else for QR */ cholmod_sparse *A, /* matrix to order and analyze */ Int *UserPerm, /* user-provided permutation, size A->nrow */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* --------------- */ cholmod_common *Common ) { double lnz_best ; Int *First, *Level, *Work4n, *Cmember, *CParent, *ColCount, *Lperm, *Parent, *Post, *Perm, *Lparent, *Lcolcount ; cholmod_factor *L ; Int k, n, ordering, method, nmethods, status, default_strategy, ncol, uncol, skip_analysis, skip_best ; Int amd_backup ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; Common->status = CHOLMOD_OK ; status = CHOLMOD_OK ; Common->selected = EMPTY ; Common->called_nd = FALSE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ n = A->nrow ; ncol = A->ncol ; uncol = (A->stype == 0) ? (A->ncol) : 0 ; /* ---------------------------------------------------------------------- */ /* set the default strategy */ /* ---------------------------------------------------------------------- */ lnz_best = (double) EMPTY ; skip_best = FALSE ; nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ; nmethods = MAX (0, nmethods) ; PRINT1 (("nmethods "ID"\n", nmethods)) ; default_strategy = (nmethods == 0) ; if (default_strategy) { /* default strategy: try UserPerm, if given. Try AMD for A, or AMD * to order A*A'. Try METIS for the symmetric case only if AMD reports * a high degree of fill-in and flop count. METIS is not tried if the * Partition Module isn't installed. If Common->default_nesdis is * TRUE, then NESDIS is used as the 3rd ordering instead. */ Common->method [0].ordering = CHOLMOD_GIVEN ;/* skip if UserPerm NULL */ Common->method [1].ordering = CHOLMOD_AMD ; Common->method [2].ordering = (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ; amd_backup = FALSE ; #ifndef NPARTITION nmethods = 3 ; #else nmethods = 2 ; #endif } else { /* If only METIS and NESDIS are selected, or if 2 or more methods are * being tried, then enable AMD backup */ amd_backup = (nmethods > 1) || (nmethods == 1 && (Common->method [0].ordering == CHOLMOD_METIS || Common->method [0].ordering == CHOLMOD_NESDIS)) ; } #ifdef NSUPERNODAL /* CHOLMOD Supernodal module not installed, just do simplicial analysis */ Common->supernodal = CHOLMOD_SIMPLICIAL ; #endif /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* Note: enough space needs to be allocated here so that routines called by * cholmod_analyze do not reallocate the space. */ /* s = 6*n + uncol */ s = CHOLMOD(mult_size_t) (n, 6, &ok) ; s = CHOLMOD(add_size_t) (s, uncol, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } CHOLMOD(allocate_work) (n, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ensure that subsequent routines, called by cholmod_analyze, do not * reallocate any workspace. This is set back to FALSE in the * FREE_WORKSPACE_AND_RETURN macro, which is the only way this function * returns to its caller. */ Common->no_workspace_reallocate = TRUE ; /* Use the last 4*n Int's in Iwork for Parent, First, Level, and Post, since * other CHOLMOD routines will use the first 2n+uncol space. The ordering * routines (cholmod_amd, cholmod_colamd, cholmod_ccolamd, cholmod_metis) * are an exception. They can use all 6n + ncol space, since the contents * of Parent, First, Level, and Post are not needed across calls to those * routines. */ Work4n = Common->Iwork ; Work4n += 2*((size_t) n) + uncol ; Parent = Work4n ; First = Work4n + n ; Level = Work4n + 2*((size_t) n) ; Post = Work4n + 3*((size_t) n) ; /* note that this assignment means that cholmod_nested_dissection, * cholmod_ccolamd, and cholmod_camd can use only the first 4n+uncol * space in Common->Iwork */ Cmember = Post ; CParent = Level ; /* ---------------------------------------------------------------------- */ /* allocate more workspace, and an empty simplicial symbolic factor */ /* ---------------------------------------------------------------------- */ L = CHOLMOD(allocate_factor) (n, Common) ; Lparent = CHOLMOD(malloc) (n, sizeof (Int), Common) ; Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ; ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ FREE_WORKSPACE_AND_RETURN ; } Lperm = L->Perm ; Lcolcount = L->ColCount ; Common->anz = EMPTY ; /* ---------------------------------------------------------------------- */ /* try all the requested ordering options and backup to AMD if needed */ /* ---------------------------------------------------------------------- */ /* turn off error handling [ */ Common->try_catch = TRUE ; for (method = 0 ; method <= nmethods ; method++) { /* ------------------------------------------------------------------ */ /* determine the method to try */ /* ------------------------------------------------------------------ */ Common->fl = EMPTY ; Common->lnz = EMPTY ; skip_analysis = FALSE ; if (method == nmethods) { /* All methods failed: backup to AMD */ if (Common->selected == EMPTY && amd_backup) { PRINT1 (("All methods requested failed: backup to AMD\n")) ; ordering = CHOLMOD_AMD ; } else { break ; } } else { ordering = Common->method [method].ordering ; } Common->current = method ; PRINT1 (("method "ID": Try method: "ID"\n", method, ordering)) ; /* ------------------------------------------------------------------ */ /* find the fill-reducing permutation */ /* ------------------------------------------------------------------ */ if (ordering == CHOLMOD_NATURAL) { /* -------------------------------------------------------------- */ /* natural ordering */ /* -------------------------------------------------------------- */ for (k = 0 ; k < n ; k++) { Perm [k] = k ; } } else if (ordering == CHOLMOD_GIVEN) { /* -------------------------------------------------------------- */ /* use given ordering of A, if provided */ /* -------------------------------------------------------------- */ if (UserPerm == NULL) { /* this is not an error condition */ PRINT1 (("skip, no user perm given\n")) ; continue ; } for (k = 0 ; k < n ; k++) { /* UserPerm is checked in cholmod_ptranspose */ Perm [k] = UserPerm [k] ; } } else if (ordering == CHOLMOD_AMD) { /* -------------------------------------------------------------- */ /* AMD ordering of A, A*A', or A(:,f)*A(:,f)' */ /* -------------------------------------------------------------- */ amd_backup = FALSE ; /* no need to try AMD twice ... */ CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; skip_analysis = TRUE ; } else if (ordering == CHOLMOD_COLAMD) { /* -------------------------------------------------------------- */ /* AMD for symmetric case, COLAMD for A*A' or A(:,f)*A(:,f)' */ /* -------------------------------------------------------------- */ if (A->stype) { CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; skip_analysis = TRUE ; } else { /* Alternative: CHOLMOD(ccolamd) (A, fset, fsize, NULL, Perm, Common) ; */ /* do not postorder, it is done later, below */ /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1)*/ CHOLMOD(colamd) (A, fset, fsize, FALSE, Perm, Common) ; } } else if (ordering == CHOLMOD_METIS) { /* -------------------------------------------------------------- */ /* use METIS_NodeND directly (via a CHOLMOD wrapper) */ /* -------------------------------------------------------------- */ #ifndef NPARTITION /* postorder parameter is false, because it will be later, below */ /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) */ Common->called_nd = TRUE ; CHOLMOD(metis) (A, fset, fsize, FALSE, Perm, Common) ; #else Common->status = CHOLMOD_NOT_INSTALLED ; #endif } else if (ordering == CHOLMOD_NESDIS) { /* -------------------------------------------------------------- */ /* use CHOLMOD's nested dissection */ /* -------------------------------------------------------------- */ /* this method is based on METIS' node bissection routine * (METIS_NodeComputeSeparator). In contrast to METIS_NodeND, * it calls CAMD or CCOLAMD on the whole graph, instead of MMD * on just the leaves. */ #ifndef NPARTITION /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow) */ Common->called_nd = TRUE ; CHOLMOD(nested_dissection) (A, fset, fsize, Perm, CParent, Cmember, Common) ; #else Common->status = CHOLMOD_NOT_INSTALLED ; #endif } else { /* -------------------------------------------------------------- */ /* invalid ordering method */ /* -------------------------------------------------------------- */ Common->status = CHOLMOD_INVALID ; PRINT1 (("No such ordering: "ID"\n", ordering)) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; if (Common->status < CHOLMOD_OK) { /* out of memory, or method failed */ status = MIN (status, Common->status) ; Common->status = CHOLMOD_OK ; continue ; } /* ------------------------------------------------------------------ */ /* analyze the ordering */ /* ------------------------------------------------------------------ */ if (!skip_analysis) { if (!CHOLMOD(analyze_ordering) (A, ordering, Perm, fset, fsize, Parent, Post, ColCount, First, Level, Common)) { /* ordering method failed; clear status and try next method */ status = MIN (status, Common->status) ; Common->status = CHOLMOD_OK ; continue ; } } ASSERT (Common->fl >= 0 && Common->lnz >= 0) ; Common->method [method].fl = Common->fl ; Common->method [method].lnz = Common->lnz ; PRINT1 (("lnz %g fl %g\n", Common->lnz, Common->fl)) ; /* ------------------------------------------------------------------ */ /* pick the best method */ /* ------------------------------------------------------------------ */ /* fl.pt. compare, but lnz can never be NaN */ if (Common->selected == EMPTY || Common->lnz < lnz_best) { Common->selected = method ; PRINT1 (("this is best so far, method "ID"\n", method)) ; L->ordering = ordering ; lnz_best = Common->lnz ; for (k = 0 ; k < n ; k++) { Lperm [k] = Perm [k] ; } /* save the results of cholmod_analyze_ordering, if it was called */ skip_best = skip_analysis ; if (!skip_analysis) { /* save the column count; becomes permanent part of L */ for (k = 0 ; k < n ; k++) { Lcolcount [k] = ColCount [k] ; } /* Parent is needed for weighted postordering and for supernodal * analysis. Does not become a permanent part of L */ for (k = 0 ; k < n ; k++) { Lparent [k] = Parent [k] ; } } } /* ------------------------------------------------------------------ */ /* determine if METIS is to be skipped */ /* ------------------------------------------------------------------ */ if (default_strategy && ordering == CHOLMOD_AMD) { if ((Common->fl < 500 * Common->lnz) || (Common->lnz < 5 * Common->anz)) { /* AMD found an ordering with less than 500 flops per nonzero in * L, or one with a fill-in ratio (nnz(L)/nnz(A)) of less than * 5. This is pretty good, and it's unlikely that METIS will do * better (this heuristic is based on tests on all symmetric * positive definite matrices in the UF sparse matrix * collection, and it works well across a wide range of * problems). METIS can take much more time than AMD. */ break ; } } } /* turn error printing back on ] */ Common->try_catch = FALSE ; /* ---------------------------------------------------------------------- */ /* return if no ordering method succeeded */ /* ---------------------------------------------------------------------- */ if (Common->selected == EMPTY) { /* All methods failed. * If two or more methods failed, they may have failed for different * reasons. Both would clear Common->status and skip to the next * method. Common->status needs to be restored here to the worst error * obtained in any of the methods. CHOLMOD_INVALID is worse * than CHOLMOD_OUT_OF_MEMORY, since the former implies something may * be wrong with the user's input. CHOLMOD_OUT_OF_MEMORY is simply an * indication of lack of resources. */ ASSERT (status < CHOLMOD_OK) ; ERROR (status, "all methods failed") ; FREE_WORKSPACE_AND_RETURN ; } /* ---------------------------------------------------------------------- */ /* do the analysis for AMD, if skipped */ /* ---------------------------------------------------------------------- */ Common->fl = Common->method [Common->selected].fl ; Common->lnz = Common->method [Common->selected].lnz ; ASSERT (Common->lnz >= 0) ; if (skip_best) { if (!CHOLMOD(analyze_ordering) (A, L->ordering, Lperm, fset, fsize, Lparent, Post, Lcolcount, First, Level, Common)) { /* out of memory, or method failed */ FREE_WORKSPACE_AND_RETURN ; } } /* ---------------------------------------------------------------------- */ /* postorder the etree, weighted by the column counts */ /* ---------------------------------------------------------------------- */ if (Common->postorder) { /* combine the fill-reducing ordering with the weighted postorder */ /* workspace: Iwork (2*nrow) */ if (CHOLMOD(postorder) (Lparent, n, Lcolcount, Post, Common) == n) { /* use First and Level as workspace [ */ Int *Wi = First, *InvPost = Level ; Int newchild, oldchild, newparent, oldparent ; for (k = 0 ; k < n ; k++) { Wi [k] = Lperm [Post [k]] ; } for (k = 0 ; k < n ; k++) { Lperm [k] = Wi [k] ; } for (k = 0 ; k < n ; k++) { Wi [k] = Lcolcount [Post [k]] ; } for (k = 0 ; k < n ; k++) { Lcolcount [k] = Wi [k] ; } for (k = 0 ; k < n ; k++) { InvPost [Post [k]] = k ; } /* updated Lparent needed only for supernodal case */ for (newchild = 0 ; newchild < n ; newchild++) { oldchild = Post [newchild] ; oldparent = Lparent [oldchild] ; newparent = (oldparent == EMPTY) ? EMPTY : InvPost [oldparent] ; Wi [newchild] = newparent ; } for (k = 0 ; k < n ; k++) { Lparent [k] = Wi [k] ; } /* done using Iwork as workspace ] */ /* L is now postordered, no longer in natural ordering */ if (L->ordering == CHOLMOD_NATURAL) { L->ordering = CHOLMOD_POSTORDERED ; } } } /* ---------------------------------------------------------------------- */ /* supernodal analysis, if requested or if selected automatically */ /* ---------------------------------------------------------------------- */ #ifndef NSUPERNODAL if (Common->supernodal > CHOLMOD_AUTO || (Common->supernodal == CHOLMOD_AUTO && Common->lnz > 0 && (Common->fl / Common->lnz) >= Common->supernodal_switch)) { cholmod_sparse *S, *F, *A2, *A1 ; permute_matrices (A, L->ordering, Lperm, fset, fsize, TRUE, &A1, &A2, &S, &F, Common) ; /* workspace: Flag (nrow), Head (nrow), Iwork (5*nrow) */ CHOLMOD(super_symbolic2) (for_cholesky, S, F, Lparent, L, Common) ; PRINT1 (("status %d\n", Common->status)) ; CHOLMOD(free_sparse) (&A1, Common) ; CHOLMOD(free_sparse) (&A2, Common) ; } #endif /* ---------------------------------------------------------------------- */ /* free temporary matrices and workspace, and return result L */ /* ---------------------------------------------------------------------- */ FREE_WORKSPACE_AND_RETURN ; }
cholmod_sparse *CHOLMOD(speye) ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Az ; cholmod_sparse *A ; Int *Ap, *Ai ; Int j, n ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate the matrix */ /* ---------------------------------------------------------------------- */ n = MIN (nrow, ncol) ; A = CHOLMOD(allocate_sparse) (nrow, ncol, n, TRUE, TRUE, 0, xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory or inputs invalid */ } /* ---------------------------------------------------------------------- */ /* create the identity matrix */ /* ---------------------------------------------------------------------- */ Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; for (j = 0 ; j < n ; j++) { Ap [j] = j ; } for (j = n ; j <= ((Int) ncol) ; j++) { Ap [j] = n ; } for (j = 0 ; j < n ; j++) { Ai [j] = j ; } switch (xtype) { case CHOLMOD_REAL: for (j = 0 ; j < n ; j++) { Ax [j] = 1 ; } break ; case CHOLMOD_COMPLEX: for (j = 0 ; j < n ; j++) { Ax [2*j ] = 1 ; Ax [2*j+1] = 0 ; } break ; case CHOLMOD_ZOMPLEX: for (j = 0 ; j < n ; j++) { Ax [j] = 1 ; } for (j = 0 ; j < n ; j++) { Az [j] = 0 ; } break ; } return (A) ; }
cholmod_sparse *CHOLMOD(horzcat) ( /* ---- input ---- */ cholmod_sparse *A, /* left matrix to concatenate */ cholmod_sparse *B, /* right matrix to concatenate */ int values, /* if TRUE compute the numerical values of C */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Bx, *Cx ; Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Cp, *Ci ; cholmod_sparse *C, *A2, *B2 ; Int apacked, bpacked, ancol, bncol, ncol, nrow, anz, bnz, nz, j, p, pend, pdest ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_NULL (B, NULL) ; values = values && (A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; if (A->nrow != B->nrow) { /* A and B must have the same number of rows */ ERROR (CHOLMOD_INVALID, "A and B must have same # rows") ; return (NULL) ; } /* A and B must have the same numerical type if values is TRUE (both must * be CHOLMOD_REAL, this is implicitly checked above) */ Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ ancol = A->ncol ; bncol = B->ncol ; nrow = A->nrow ; CHOLMOD(allocate_work) (0, MAX3 (nrow, ancol, bncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ /* convert A to unsymmetric, if necessary */ A2 = NULL ; if (A->stype != 0) { /* workspace: Iwork (max (A->nrow,A->ncol)) */ A2 = CHOLMOD(copy) (A, 0, values, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } A = A2 ; } /* convert B to unsymmetric, if necessary */ B2 = NULL ; if (B->stype != 0) { /* workspace: Iwork (max (B->nrow,B->ncol)) */ B2 = CHOLMOD(copy) (B, 0, values, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ CHOLMOD(free_sparse) (&A2, Common) ; return (NULL) ; } B = B2 ; } Ap = A->p ; Anz = A->nz ; Ai = A->i ; Ax = A->x ; apacked = A->packed ; Bp = B->p ; Bnz = B->nz ; Bi = B->i ; Bx = B->x ; bpacked = B->packed ; /* ---------------------------------------------------------------------- */ /* allocate C */ /* ---------------------------------------------------------------------- */ anz = CHOLMOD(nnz) (A, Common) ; bnz = CHOLMOD(nnz) (B, Common) ; ncol = ancol + bncol ; nz = anz + bnz ; C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, A->sorted && B->sorted, TRUE, 0, values ? A->xtype : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; return (NULL) ; } Cp = C->p ; Ci = C->i ; Cx = C->x ; /* ---------------------------------------------------------------------- */ /* C = [A , B] */ /* ---------------------------------------------------------------------- */ pdest = 0 ; /* copy A as the first A->ncol columns of C */ for (j = 0 ; j < ancol ; j++) { /* A(:,j) is the jth column of C */ p = Ap [j] ; pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; Cp [j] = pdest ; for ( ; p < pend ; p++) { Ci [pdest] = Ai [p] ; if (values) Cx [pdest] = Ax [p] ; pdest++ ; } } /* copy B as the next B->ncol columns of C */ for (j = 0 ; j < bncol ; j++) { /* B(:,j) is the (ancol+j)th column of C */ p = Bp [j] ; pend = (bpacked) ? (Bp [j+1]) : (p + Bnz [j]) ; Cp [ancol + j] = pdest ; for ( ; p < pend ; p++) { Ci [pdest] = Bi [p] ; if (values) Cx [pdest] = Bx [p] ; pdest++ ; } } Cp [ncol] = pdest ; ASSERT (pdest == anz + bnz) ; /* ---------------------------------------------------------------------- */ /* free the unsymmetric copies of A and B, and return C */ /* ---------------------------------------------------------------------- */ CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; return (C) ; }
cholmod_sparse *CHOLMOD(allocate_sparse) ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ size_t nzmax, /* max # of nonzeros of A */ int sorted, /* TRUE if columns of A sorted, FALSE otherwise */ int packed, /* TRUE if A will be packed, FALSE otherwise */ int stype, /* stype of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *A ; Int *Ap, *Anz ; size_t nzmax0 ; Int j ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; if (stype != 0 && nrow != ncol) { ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ; return (NULL) ; } if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "xtype invalid") ; return (NULL) ; } /* ensure the dimensions do not cause integer overflow */ (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ; if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate header */ /* ---------------------------------------------------------------------- */ A = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } PRINT1 (("cholmod_allocate_sparse %d-by-%d nzmax %d sorted %d packed %d" " xtype %d\n", nrow, ncol, nzmax, sorted, packed, xtype)) ; nzmax = MAX (1, nzmax) ; A->nrow = nrow ; A->ncol = ncol ; A->nzmax = nzmax ; A->packed = packed ; /* default is packed (A->nz not present) */ A->stype = stype ; A->itype = ITYPE ; A->xtype = xtype ; A->dtype = DTYPE ; A->nz = NULL ; A->p = NULL ; A->i = NULL ; A->x = NULL ; A->z = NULL ; /* A 1-by-m matrix always has sorted columns */ A->sorted = (nrow <= 1) ? TRUE : sorted ; /* ---------------------------------------------------------------------- */ /* allocate the matrix itself */ /* ---------------------------------------------------------------------- */ /* allocate O(ncol) space */ A->p = CHOLMOD(malloc) (((size_t) ncol)+1, sizeof (Int), Common) ; if (!packed) { A->nz = CHOLMOD(malloc) (ncol, sizeof (Int), Common) ; } /* allocate O(nz) space */ nzmax0 = 0 ; CHOLMOD(realloc_multiple) (nzmax, 1, xtype, &(A->i), NULL, &(A->x), &(A->z), &nzmax0, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&A, Common) ; return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* initialize A->p and A->nz so that A is an empty matrix */ /* ---------------------------------------------------------------------- */ Ap = A->p ; for (j = 0 ; j <= (Int) ncol ; j++) { Ap [j] = 0 ; } if (!packed) { Anz = A->nz ; for (j = 0 ; j < (Int) ncol ; j++) { Anz [j] = 0 ; } } return (A) ; }
static void NUMERIC (WDIM, r) ( int update, /* TRUE for update, FALSE for downdate */ cholmod_sparse *C, /* in packed or unpacked, and sorted form */ /* no empty columns */ Int rank, /* rank of the update/downdate */ cholmod_factor *L, /* with unit diagonal (diagonal not stored) */ /* temporary workspaces: */ double W [ ], /* n-by-WDIM dense matrix, initially zero */ Path_type Path [ ], Int npaths, Int mask [ ], /* size n */ Int maskmark, cholmod_common *Common ) { double Alpha [8] ; double *Cx, *Wpath, *W1, *a ; Int i, j, p, ccol, pend, wfirst, e, path, packed ; Int *Ci, *Cp, *Cnz ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ Ci = C->i ; Cx = C->x ; Cp = C->p ; Cnz = C->nz ; packed = C->packed ; ASSERT (IMPLIES (!packed, Cnz != NULL)) ; ASSERT (L->n == C->nrow) ; DEBUG (CHOLMOD(dump_real) ("num_d: in W:", W, WDIM, L->n, FALSE, 1,Common)); /* ---------------------------------------------------------------------- */ /* scatter C into W */ /* ---------------------------------------------------------------------- */ for (path = 0 ; path < rank ; path++) { /* W (:, path) = C (:, Path [path].col) */ ccol = Path [path].ccol ; Wpath = W + path ; PRINT1 (("Ordered Columns [path = "ID"] = "ID"\n", path, ccol)) ; p = Cp [ccol] ; pend = (packed) ? (Cp [ccol+1]) : (p + Cnz [ccol]) ; /* column C can be empty */ for ( ; p < pend ; p++) { i = Ci [p] ; ASSERT (i >= 0 && i < (Int) (C->nrow)) ; if (mask == NULL || mask [i] < maskmark) { Wpath [WDIM * i] = Cx [p] ; } PRINT1 ((" row "ID" : %g mask "ID"\n", i, Cx [p], (mask) ? mask [i] : 0)) ; } Alpha [path] = 1.0 ; } DEBUG (CHOLMOD(dump_real) ("num_d: W:", W, WDIM, L->n, FALSE, 1,Common)) ; /* ---------------------------------------------------------------------- */ /* numeric update/downdate of the paths */ /* ---------------------------------------------------------------------- */ /* for each disjoint subpath in Tbar in DFS order do */ for (path = rank ; path < npaths ; path++) { /* determine which columns of W to use */ wfirst = Path [path].wfirst ; e = Path [path].end ; j = Path [path].start ; ASSERT (e >= 0 && e < (Int) (L->n)) ; ASSERT (j >= 0 && j < (Int) (L->n)) ; W1 = W + wfirst ; /* pointer to row 0, column wfirst of W */ a = Alpha + wfirst ; /* pointer to Alpha [wfirst] */ PRINT1 (("Numerical update/downdate of path "ID"\n", path)) ; PRINT1 (("start "ID" end "ID" wfirst "ID" rank "ID" ccol "ID"\n", j, e, wfirst, Path [path].rank, Path [path].ccol)) ; #if WDIM == 1 NUMERIC (WDIM,1) (update, j, e, a, W1, L, Common) ; #else switch (Path [path].rank) { case 1: NUMERIC (WDIM,1) (update, j, e, a, W1, L, Common) ; break ; #if WDIM >= 2 case 2: NUMERIC (WDIM,2) (update, j, e, a, W1, L, Common) ; break ; #endif #if WDIM >= 4 case 3: NUMERIC (WDIM,3) (update, j, e, a, W1, L, Common) ; break ; case 4: NUMERIC (WDIM,4) (update, j, e, a, W1, L, Common) ; break ; #endif #if WDIM == 8 case 5: NUMERIC (WDIM,5) (update, j, e, a, W1, L, Common) ; break ; case 6: NUMERIC (WDIM,6) (update, j, e, a, W1, L, Common) ; break ; case 7: NUMERIC (WDIM,7) (update, j, e, a, W1, L, Common) ; break ; case 8: NUMERIC (WDIM,8) (update, j, e, a, W1, L, Common) ; break ; #endif } #endif } }
int CHOLMOD(row_subtree) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ size_t krow, /* row k of L */ Int *Parent, /* elimination tree */ /* ---- output --- */ cholmod_sparse *R, /* pattern of L(k,:), 1-by-n with R->nzmax >= n */ /* --------------- */ cholmod_common *Common ) { Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Fp, *Fi, *Fnz ; Int p, pend, parent, t, stype, nrow, k, pf, pfend, Fpacked, packed, sorted, top, len, i, mark ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (R, FALSE) ; RETURN_IF_NULL (Parent, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; stype = A->stype ; if (stype == 0) { RETURN_IF_NULL (F, FALSE) ; RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; } if (krow >= A->nrow) { ERROR (CHOLMOD_INVALID, "subtree: k invalid") ; return (FALSE) ; } if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax) { ERROR (CHOLMOD_INVALID, "subtree: R invalid") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if (stype > 0) { /* symmetric upper case: F is not needed. It may be NULL */ Fp = NULL ; Fi = NULL ; Fnz = NULL ; Fpacked = TRUE ; } else if (stype == 0) { /* unsymmetric case: F is required. */ Fp = F->p ; Fi = F->i ; Fnz = F->nz ; Fpacked = F->packed ; } else { /* symmetric lower triangular form not supported */ ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; return (FALSE) ; } Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; sorted = A->sorted ; k = krow ; Stack = R->i ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Flag = Common->Flag ; /* size nrow, Flag [i] < mark must hold */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; /* ---------------------------------------------------------------------- */ /* compute the pattern of L(k,:) */ /* ---------------------------------------------------------------------- */ top = nrow ; /* Stack is empty */ Flag [k] = mark ; /* do not include diagonal entry in Stack */ #define SCATTER /* do not scatter numerical values */ #define PARENT(i) Parent [i] /* use Parent for etree */ if (stype != 0) { /* scatter kth col of triu (A), get pattern L(k,:) */ p = Ap [k] ; pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; SUBTREE ; } else { /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ pf = Fp [k] ; pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; for ( ; pf < pfend ; pf++) { /* get nonzero entry F (t,k) */ t = Fi [pf] ; p = Ap [t] ; pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; SUBTREE ; } } #undef SCATTER #undef PARENT /* shift the stack upwards, to the first part of R */ len = nrow - top ; for (i = 0 ; i < len ; i++) { Stack [i] = Stack [top + i] ; } Rp = R->p ; Rp [0] = 0 ; Rp [1] = len ; R->sorted = FALSE ; CHOLMOD(clear_flag) (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; return (TRUE) ; }
void amdtest (cholmod_sparse *A) { double Control [AMD_CONTROL], Info [AMD_INFO], alpha ; Int *P, *Cp, *Ci, *Sp, *Si, *Bp, *Bi, *Ep, *Ei, *Fp, *Fi, *Len, *Nv, *Next, *Head, *Elen, *Deg, *Wi, *W, *Flag ; cholmod_sparse *C, *B, *S, *E, *F ; Int i, j, n, nrow, ncol, ok, cnz, bnz, p, trial, sorted ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ printf ("\nAMD test\n") ; if (A == NULL) { return ; } if (A->stype) { B = CHOLMOD(copy) (A, 0, 0, cm) ; } else { B = CHOLMOD(aat) (A, NULL, 0, 0, cm) ; } if (A->nrow != A->ncol) { F = CHOLMOD(copy_sparse) (B, cm) ; OK (F->nrow == F->ncol) ; CHOLMOD(sort) (F, cm) ; } else { /* A is square and unsymmetric, and may have entries in A+A' that * are not in A */ F = CHOLMOD(copy_sparse) (A, cm) ; CHOLMOD(sort) (F, cm) ; } C = CHOLMOD(copy_sparse) (B, cm) ; nrow = C->nrow ; ncol = C->ncol ; n = nrow ; OK (nrow == ncol) ; Cp = C->p ; Ci = C->i ; Bp = B->p ; Bi = B->i ; /* ---------------------------------------------------------------------- */ /* S = sorted form of B, using AMD_preprocess */ /* ---------------------------------------------------------------------- */ cnz = CHOLMOD(nnz) (C, cm) ; S = CHOLMOD(allocate_sparse) (n, n, cnz, TRUE, TRUE, 0, CHOLMOD_PATTERN, cm); Sp = S->p ; Si = S->i ; W = CHOLMOD(malloc) (n, sizeof (Int), cm) ; Flag = CHOLMOD(malloc) (n, sizeof (Int), cm) ; AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; /* ---------------------------------------------------------------------- */ /* allocate workspace for amd */ /* ---------------------------------------------------------------------- */ P = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; Len = CHOLMOD(malloc) (n, sizeof (Int), cm) ; Nv = CHOLMOD(malloc) (n, sizeof (Int), cm) ; Next = CHOLMOD(malloc) (n, sizeof (Int), cm) ; Head = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; Elen = CHOLMOD(malloc) (n, sizeof (Int), cm) ; Deg = CHOLMOD(malloc) (n, sizeof (Int), cm) ; Wi = CHOLMOD(malloc) (n, sizeof (Int), cm) ; /* ---------------------------------------------------------------------- */ for (sorted = 0 ; sorted <= 1 ; sorted++) { if (sorted) CHOLMOD(sort) (C, cm) ; Cp = C->p ; Ci = C->i ; /* ------------------------------------------------------------------ */ /* order C with AMD_order */ /* ------------------------------------------------------------------ */ AMD_defaults (Control) ; AMD_defaults (NULL) ; AMD_control (Control) ; AMD_control (NULL) ; AMD_info (NULL) ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; printf ("amd return value: "ID"\n", ok) ; AMD_info (Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation", cm)) ; /* no dense rows/cols */ alpha = Control [AMD_DENSE] ; Control [AMD_DENSE] = -1 ; AMD_control (Control) ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; printf ("amd return value: "ID"\n", ok) ; AMD_info (Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (alpha=-1)", cm)) ; /* many dense rows/cols */ Control [AMD_DENSE] = 0 ; AMD_control (Control) ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; printf ("amd return value: "ID"\n", ok) ; AMD_info (Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (alpha=0)", cm)) ; Control [AMD_DENSE] = alpha ; /* no aggressive absorption */ Control [AMD_AGGRESSIVE] = FALSE ; AMD_control (Control) ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; printf ("amd return value: "ID"\n", ok) ; AMD_info (Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (no agg) ", cm)) ; Control [AMD_AGGRESSIVE] = TRUE ; /* ------------------------------------------------------------------ */ /* order F with AMD_order */ /* ------------------------------------------------------------------ */ Fp = F->p ; Fi = F->i ; ok = AMD_order (n, Fp, Fi, P, Control, Info) ; printf ("amd return value: "ID"\n", ok) ; AMD_info (Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; OK (CHOLMOD(print_perm) (P, n, n, "F: AMD permutation", cm)) ; /* ------------------------------------------------------------------ */ /* order S with AMD_order */ /* ------------------------------------------------------------------ */ ok = AMD_order (n, Sp, Si, P, Control, Info) ; printf ("amd return value: "ID"\n", ok) ; AMD_info (Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation", cm)) ; /* ------------------------------------------------------------------ */ /* order E with AMD_2, which destroys its contents */ /* ------------------------------------------------------------------ */ E = CHOLMOD(copy) (B, 0, -1, cm) ; /* remove diagonal entries */ bnz = CHOLMOD(nnz) (E, cm) ; /* add the bare minimum extra space to E */ ok = CHOLMOD(reallocate_sparse) (bnz + n, E, cm) ; OK (ok) ; Ep = E->p ; Ei = E->i ; for (j = 0 ; j < n ; j++) { Len [j] = Ep [j+1] - Ep [j] ; } printf ("calling AMD_2:\n") ; if (n > 0) { AMD_2 (n, Ep, Ei, Len, E->nzmax, Ep [n], Nv, Next, P, Head, Elen, Deg, Wi, Control, Info) ; AMD_info (Info) ; OK (CHOLMOD(print_perm) (P, n, n, "AMD2 permutation", cm)) ; } /* ------------------------------------------------------------------ */ /* error tests */ /* ------------------------------------------------------------------ */ ok = AMD_order (n, Cp, Ci, P, Control, Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; ok = AMD_order (-1, Cp, Ci, P, Control, Info) ; OK (ok == AMD_INVALID); ok = AMD_order (0, Cp, Ci, P, Control, Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; ok = AMD_order (n, NULL, Ci, P, Control, Info) ; OK (ok == AMD_INVALID); ok = AMD_order (n, Cp, NULL, P, Control, Info) ; OK (ok == AMD_INVALID); ok = AMD_order (n, Cp, Ci, NULL, Control, Info) ; OK (ok == AMD_INVALID); if (n > 0) { printf ("AMD error tests:\n") ; p = Cp [n] ; Cp [n] = -1 ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; OK (ok == AMD_INVALID) ; if (Size_max/2 == Int_max) { Cp [n] = Int_max ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; printf ("AMD status is "ID"\n", ok) ; OK (ok == AMD_OUT_OF_MEMORY) ; } Cp [n] = p ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; if (Cp [n] > 0) { printf ("Mangle column zero:\n") ; i = Ci [0] ; Ci [0] = -1 ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; AMD_info (Info) ; OK (ok == AMD_INVALID) ; Ci [0] = i ; } } ok = AMD_valid (n, n, Sp, Si) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; ok = AMD_valid (-1, n, Sp, Si) ; OK (ok == AMD_INVALID) ; ok = AMD_valid (n, -1, Sp, Si) ; OK (ok == AMD_INVALID) ; ok = AMD_valid (n, n, NULL, Si) ; OK (ok == AMD_INVALID) ; ok = AMD_valid (n, n, Sp, NULL) ; OK (ok == AMD_INVALID) ; if (n > 0 && Sp [n] > 0) { p = Sp [n] ; Sp [n] = -1 ; ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; Sp [n] = p ; p = Sp [0] ; Sp [0] = -1 ; ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; Sp [0] = p ; p = Sp [1] ; Sp [1] = -1 ; ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; Sp [1] = p ; i = Si [0] ; Si [0] = -1 ; ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; Si [0] = i ; } ok = AMD_valid (n, n, Sp, Si) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_OK) ; if (n > 0 && Bp [n] > 0) { p = Bp [n] ; Bp [n] = -1 ; ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; Bp [n] = p ; p = Bp [1] ; Bp [1] = -1 ; ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; Bp [1] = p ; i = Bi [0] ; Bi [0] = -1 ; ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; Bi [0] = i ; } AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; Info [AMD_STATUS] = 777 ; AMD_info (Info) ; /* ------------------------------------------------------------------ */ /* memory tests */ /* ------------------------------------------------------------------ */ if (n > 0) { normal_memory_handler ( ) ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; test_memory_handler ( ) ; for (trial = 0 ; trial < 6 ; trial++) { my_tries = trial ; printf ("AMD memory trial "ID"\n", trial) ; ok = AMD_order (n, Cp, Ci, P, Control, Info) ; AMD_info (Info) ; OK (ok == AMD_OUT_OF_MEMORY || (sorted ? (ok == AMD_OK) : (ok >= AMD_OK))) ; } normal_memory_handler ( ) ; OK (CHOLMOD(print_perm) (P, n, n, "AMD2 permutation", cm)) ; } CHOLMOD(free_sparse) (&E, cm) ; } /* ---------------------------------------------------------------------- */ /* free everything */ /* ---------------------------------------------------------------------- */ CHOLMOD(free) (n, sizeof (Int), Len, cm) ; CHOLMOD(free) (n, sizeof (Int), Nv, cm) ; CHOLMOD(free) (n, sizeof (Int), Next, cm) ; CHOLMOD(free) (n+1, sizeof (Int), Head, cm) ; CHOLMOD(free) (n, sizeof (Int), Elen, cm) ; CHOLMOD(free) (n, sizeof (Int), Deg, cm) ; CHOLMOD(free) (n, sizeof (Int), Wi, cm) ; CHOLMOD(free) (n+1, sizeof (Int), P, cm) ; CHOLMOD(free) (n, sizeof (Int), W, cm) ; CHOLMOD(free) (n, sizeof (Int), Flag, cm) ; CHOLMOD(free_sparse) (&S, cm) ; CHOLMOD(free_sparse) (&B, cm) ; CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&F, cm) ; }
int CHOLMOD(rowfac_mask) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ double beta [2], /* factorize beta*I+A or beta*I+AA' */ size_t kstart, /* first row to factorize */ size_t kend, /* last row to factorize is kend-1 */ Int *mask, /* size A->nrow. if mask[i] >= 0 row i is set to zero */ Int *RLinkUp, /* size A->nrow. link list of rows to compute */ /* ---- in/out --- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) { Int n ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (L->xtype != CHOLMOD_PATTERN && A->xtype != L->xtype) { ERROR (CHOLMOD_INVALID, "xtype of A and L do not match") ; return (FALSE) ; } if (L->is_super) { ERROR (CHOLMOD_INVALID, "can only do simplicial factorization"); return (FALSE) ; } if (A->stype == 0) { RETURN_IF_NULL (F, FALSE) ; if (A->xtype != F->xtype) { ERROR (CHOLMOD_INVALID, "xtype of A and F do not match") ; return (FALSE) ; } } if (A->stype < 0) { /* symmetric lower triangular form not supported */ ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; return (FALSE) ; } if (kend > L->n) { ERROR (CHOLMOD_INVALID, "kend invalid") ; return (FALSE) ; } if (A->nrow != L->n) { ERROR (CHOLMOD_INVALID, "dimensions of A and L do not match") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; Common->rowfacfl = 0 ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* Xwork is of size n for the real case, 2*n for complex/zomplex */ n = L->n ; /* s = ((A->xtype != CHOLMOD_REAL) ? 2:1)*n */ s = CHOLMOD(mult_size_t) (n, ((A->xtype != CHOLMOD_REAL) ? 2:1), &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (n, n, s, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, A->nrow, Common)) ; /* ---------------------------------------------------------------------- */ /* factorize the matrix, using template routine */ /* ---------------------------------------------------------------------- */ if (RLinkUp == NULL) { switch (A->xtype) { case CHOLMOD_REAL: ok = r_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; break ; case CHOLMOD_COMPLEX: ok = c_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; break ; case CHOLMOD_ZOMPLEX: ok = z_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; break ; } } else { switch (A->xtype) { case CHOLMOD_REAL: ok = r_cholmod_rowfac_mask (A, F, beta, kstart, kend, mask, RLinkUp, L, Common) ; break ; case CHOLMOD_COMPLEX: ok = c_cholmod_rowfac_mask (A, F, beta, kstart, kend, mask, RLinkUp, L, Common) ; break ; case CHOLMOD_ZOMPLEX: ok = z_cholmod_rowfac_mask (A, F, beta, kstart, kend, mask, RLinkUp, L, Common) ; break ; } } return (ok) ; }
int CHOLMOD(reallocate_column) ( /* ---- input ---- */ size_t j, /* the column to reallocate */ size_t need, /* required size of column j */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) { double xneed ; double *Lx, *Lz ; Int *Lp, *Lprev, *Lnext, *Li, *Lnz ; Int n, pold, pnew, len, k, tail ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; if (L->is_super) { ERROR (CHOLMOD_INVALID, "L must be simplicial") ; return (FALSE) ; } n = L->n ; if (j >= L->n || need == 0) { ERROR (CHOLMOD_INVALID, "j invalid") ; return (FALSE) ; /* j out of range */ } Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start colrealloc", Common)) ; /* ---------------------------------------------------------------------- */ /* increase the size of L if needed */ /* ---------------------------------------------------------------------- */ /* head = n+1 ; */ tail = n ; Lp = L->p ; Lnz = L->nz ; Lprev = L->prev ; Lnext = L->next ; ASSERT (Lnz != NULL) ; ASSERT (Lnext != NULL && Lprev != NULL) ; PRINT1 (("col %g need %g\n", (double) j, (double) need)) ; /* column j cannot have more than n-j entries if all entries are present */ need = MIN (need, n-j) ; /* compute need in double to avoid integer overflow */ if (Common->grow1 >= 1.0) { xneed = (double) need ; xneed = Common->grow1 * xneed + Common->grow2 ; xneed = MIN (xneed, n-j) ; need = (Int) xneed ; } PRINT1 (("really new need %g current %g\n", (double) need, (double) (Lp [Lnext [j]] - Lp [j]))) ; ASSERT (need >= 1 && need <= n-j) ; if (Lp [Lnext [j]] - Lp [j] >= (Int) need) { /* no need to reallocate the column, it's already big enough */ PRINT1 (("colrealloc: quick return %g %g\n", (double) (Lp [Lnext [j]] - Lp [j]), (double) need)) ; return (TRUE) ; } if (Lp [tail] + need > L->nzmax) { /* use double to avoid integer overflow */ xneed = (double) need ; if (Common->grow0 < 1.2) /* fl. pt. compare, false if NaN */ { /* if grow0 is less than 1.2 or NaN, don't use it */ xneed = 1.2 * (((double) L->nzmax) + xneed + 1) ; } else { xneed = Common->grow0 * (((double) L->nzmax) + xneed + 1) ; } if (xneed > Size_max || !CHOLMOD(reallocate_factor) ((Int) xneed, L, Common)) { /* out of memory, convert to simplicial symbolic */ CHOLMOD(change_factor) (CHOLMOD_PATTERN, L->is_ll, FALSE, TRUE, TRUE, L, Common) ; ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory; L now symbolic") ; return (FALSE) ; /* out of memory */ } PRINT1 (("\n=== GROW L from %g to %g\n", (double) L->nzmax, (double) xneed)) ; /* pack all columns so that each column has at most grow2 free space */ CHOLMOD(pack_factor) (L, Common) ; ASSERT (Common->status == CHOLMOD_OK) ; Common->nrealloc_factor++ ; } /* ---------------------------------------------------------------------- */ /* reallocate the column */ /* ---------------------------------------------------------------------- */ Common->nrealloc_col++ ; Li = L->i ; Lx = L->x ; Lz = L->z ; /* remove j from its current position in the list */ Lnext [Lprev [j]] = Lnext [j] ; Lprev [Lnext [j]] = Lprev [j] ; /* place j at the end of the list */ Lnext [Lprev [tail]] = j ; Lprev [j] = Lprev [tail] ; Lnext [j] = n ; Lprev [tail] = j ; /* L is no longer monotonic; columns are out-of-order */ L->is_monotonic = FALSE ; /* allocate space for column j */ pold = Lp [j] ; pnew = Lp [tail] ; Lp [j] = pnew ; Lp [tail] += need ; /* copy column j to the new space */ len = Lnz [j] ; for (k = 0 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; } if (L->xtype == CHOLMOD_REAL) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for (k = 0 ; k < len ; k++) { Lx [2*(pnew + k) ] = Lx [2*(pold + k) ] ; Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ; } } else if (L->xtype == CHOLMOD_ZOMPLEX) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; Lz [pnew + k] = Lz [pold + k] ; } } DEBUG (CHOLMOD(dump_factor) (L, "colrealloc done", Common)) ; /* successful reallocation of column j of L */ return (TRUE) ; }