GLOBAL Int UMF_triplet_map_x #else GLOBAL Int UMF_triplet_map_nox #endif #else #ifdef DO_VALUES GLOBAL Int UMF_triplet_nomap_x #else GLOBAL Int UMF_triplet_nomap_nox #endif #endif ( Int n_row, Int n_col, Int nz, const Int Ti [ ], /* size nz */ const Int Tj [ ], /* size nz */ Int Ap [ ], /* size n_col + 1 */ Int Ai [ ], /* size nz */ Int Rp [ ], /* size n_row + 1 */ Int Rj [ ], /* size nz */ Int W [ ], /* size max (n_row, n_col) */ Int RowCount [ ] /* size n_row */ #ifdef DO_VALUES , const double Tx [ ] /* size nz */ , double Ax [ ] /* size nz */ , double Rx [ ] /* size nz */ #ifdef COMPLEX , const double Tz [ ] /* size nz */ , double Az [ ] /* size nz */ , double Rz [ ] /* size nz */ #endif #endif #ifdef DO_MAP , Int Map [ ] /* size nz */ , Int Map2 [ ] /* size nz */ #endif ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int i, j, k, p, cp, p1, p2, pdest, pj ; #ifdef DO_MAP Int duplicates ; #endif #ifdef DO_VALUES #ifdef COMPLEX Int split = SPLIT (Tz) && SPLIT (Az) && SPLIT (Rz) ; #endif #endif /* ---------------------------------------------------------------------- */ /* count the entries in each row (also counting duplicates) */ /* ---------------------------------------------------------------------- */ /* use W as workspace for row counts (including duplicates) */ for (i = 0 ; i < n_row ; i++) { W [i] = 0 ; } for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i < 0 || i >= n_row || j < 0 || j >= n_col) { return (UMFPACK_ERROR_invalid_matrix) ; } W [i]++ ; #ifndef NDEBUG DEBUG1 ((ID " triplet: "ID" "ID" ", k, i, j)) ; #ifdef DO_VALUES { Entry tt ; ASSIGN (tt, Tx, Tz, k, split) ; EDEBUG2 (tt) ; DEBUG1 (("\n")) ; } #endif #endif } /* ---------------------------------------------------------------------- */ /* compute the row pointers */ /* ---------------------------------------------------------------------- */ Rp [0] = 0 ; for (i = 0 ; i < n_row ; i++) { Rp [i+1] = Rp [i] + W [i] ; W [i] = Rp [i] ; } /* W is now equal to the row pointers */ /* ---------------------------------------------------------------------- */ /* construct the row form */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < nz ; k++) { p = W [Ti [k]]++ ; #ifdef DO_MAP Map [k] = p ; #endif Rj [p] = Tj [k] ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Rx [p] = Tx [k] ; Rz [p] = Tz [k] ; } else { Rx [2*p ] = Tx [2*k ] ; Rx [2*p+1] = Tx [2*k+1] ; } #else Rx [p] = Tx [k] ; #endif #endif } /* Rp stays the same, but W [i] is advanced to the start of row i+1 */ #ifndef NDEBUG for (i = 0 ; i < n_row ; i++) { ASSERT (W [i] == Rp [i+1]) ; } #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("First row map: Map ["ID"] = "ID"\n", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (j == Rj [p]) ; ASSERT (Rp [i] <= p && p < Rp [i+1]) ; } #endif #endif /* ---------------------------------------------------------------------- */ /* sum up duplicates */ /* ---------------------------------------------------------------------- */ /* use W [j] to hold position in Ri/Rx/Rz of a_ij, for row i [ */ for (j = 0 ; j < n_col ; j++) { W [j] = EMPTY ; } #ifdef DO_MAP duplicates = FALSE ; #endif for (i = 0 ; i < n_row ; i++) { p1 = Rp [i] ; p2 = Rp [i+1] ; pdest = p1 ; /* At this point, W [j] < p1 holds true for all columns j, */ /* because Ri/Rx/Rz is stored in row oriented order. */ #ifndef NDEBUG if (UMF_debug >= -2) { for (j = 0 ; j < n_col ; j++) { ASSERT (W [j] < p1) ; } } #endif for (p = p1 ; p < p2 ; p++) { j = Rj [p] ; ASSERT (j >= 0 && j < n_col) ; pj = W [j] ; if (pj >= p1) { /* this column index, j, is already in row i, at position pj */ ASSERT (pj < p) ; ASSERT (Rj [pj] == j) ; #ifdef DO_MAP Map2 [p] = pj ; duplicates = TRUE ; #endif #ifdef DO_VALUES /* sum the entry */ #ifdef COMPLEX if (split) { Rx [pj] += Rx [p] ; Rz [pj] += Rz [p] ; } else { Rx[2*pj ] += Rx[2*p ] ; Rx[2*pj+1] += Rx[2*p+1] ; } #else Rx [pj] += Rx [p] ; #endif #endif } else { /* keep the entry */ /* also keep track in W[j] of position of a_ij for case above */ W [j] = pdest ; #ifdef DO_MAP Map2 [p] = pdest ; #endif /* no need to move the entry if pdest is equal to p */ if (pdest != p) { Rj [pdest] = j ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Rx [pdest] = Rx [p] ; Rz [pdest] = Rz [p] ; } else { Rx [2*pdest ] = Rx [2*p ] ; Rx [2*pdest+1] = Rx [2*p+1] ; } #else Rx [pdest] = Rx [p] ; #endif #endif } pdest++ ; } } RowCount [i] = pdest - p1 ; } /* done using W for position of a_ij ] */ /* ---------------------------------------------------------------------- */ /* merge Map and Map2 into a single Map */ /* ---------------------------------------------------------------------- */ #ifdef DO_MAP if (duplicates) { for (k = 0 ; k < nz ; k++) { Map [k] = Map2 [Map [k]] ; } } #ifndef NDEBUG else { /* no duplicates, so no need to recompute Map */ for (k = 0 ; k < nz ; k++) { ASSERT (Map2 [k] == k) ; } } for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("Second row map: Map ["ID"] = "ID"\n", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (j == Rj [p]) ; ASSERT (Rp [i] <= p && p < Rp [i+1]) ; } #endif #endif /* now the kth triplet maps to p = Map [k], and thus to Rj/Rx [p] */ /* ---------------------------------------------------------------------- */ /* count the entries in each column */ /* ---------------------------------------------------------------------- */ /* [ use W as work space for column counts of A */ for (j = 0 ; j < n_col ; j++) { W [j] = 0 ; } for (i = 0 ; i < n_row ; i++) { for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++) { j = Rj [p] ; ASSERT (j >= 0 && j < n_col) ; W [j]++ ; } } /* ---------------------------------------------------------------------- */ /* create the column pointers */ /* ---------------------------------------------------------------------- */ Ap [0] = 0 ; for (j = 0 ; j < n_col ; j++) { Ap [j+1] = Ap [j] + W [j] ; } /* done using W as workspace for column counts of A ] */ for (j = 0 ; j < n_col ; j++) { W [j] = Ap [j] ; } /* ---------------------------------------------------------------------- */ /* construct the column form */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i < n_row ; i++) { for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++) { cp = W [Rj [p]]++ ; #ifdef DO_MAP Map2 [p] = cp ; #endif Ai [cp] = i ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Ax [cp] = Rx [p] ; Az [cp] = Rz [p] ; } else { Ax [2*cp ] = Rx [2*p ] ; Ax [2*cp+1] = Rx [2*p+1] ; } #else Ax [cp] = Rx [p] ; #endif #endif } } /* ---------------------------------------------------------------------- */ /* merge Map and Map2 into a single Map */ /* ---------------------------------------------------------------------- */ #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { Map [k] = Map2 [Map [k]] ; } #endif /* now the kth triplet maps to p = Map [k], and thus to Ai/Ax [p] */ #ifndef NDEBUG for (j = 0 ; j < n_col ; j++) { ASSERT (W [j] == Ap [j+1]) ; } UMF_dump_col_matrix ( #ifdef DO_VALUES Ax, #ifdef COMPLEX Az, #endif #else (double *) NULL, #ifdef COMPLEX (double *) NULL, #endif #endif Ai, Ap, n_row, n_col, nz) ; #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("Col map: Map ["ID"] = "ID"\t", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (i == Ai [p]) ; DEBUG1 ((" i "ID" j "ID" Ap[j] "ID" p "ID" Ap[j+1] "ID"\n", i, j, Ap [j], p, Ap [j+1])) ; ASSERT (Ap [j] <= p && p < Ap [j+1]) ; } #endif #endif return (UMFPACK_OK) ; }
GLOBAL Int UMF_extend_front ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int j, i, *Frows, row, col, *Wrow, fnr2, fnc2, *Frpos, *Fcpos, *Fcols, fnrows_extended, rrdeg, ccdeg, fncols_extended, fnr_curr, fnc_curr, fnrows, fncols, pos, fnpiv, *Wm ; Entry *Wx, *Wy, *Fu, *Fl ; /* ---------------------------------------------------------------------- */ /* get current frontal matrix and check for frontal growth */ /* ---------------------------------------------------------------------- */ fnpiv = Work->fnpiv ; #ifndef NDEBUG DEBUG2 (("EXTEND FRONT\n")) ; DEBUG2 (("Work->fnpiv "ID"\n", fnpiv)) ; ASSERT (Work->Flblock == Work->Flublock + Work->nb*Work->nb) ; ASSERT (Work->Fublock == Work->Flblock + Work->fnr_curr*Work->nb) ; ASSERT (Work->Fcblock == Work->Fublock + Work->nb*Work->fnc_curr) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Work->Fcblock, Work->fnr_curr, Work->fnrows, Work->fncols) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Work->Flblock, Work->fnr_curr, Work->fnrows, fnpiv); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Work->Fublock, Work->fnc_curr, Work->fncols, fnpiv) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Work->Flublock, Work->nb, fnpiv, fnpiv) ; #endif if (Work->do_grow) { fnr2 = UMF_FRONTAL_GROWTH * Work->fnrows_new + 2 ; fnc2 = UMF_FRONTAL_GROWTH * Work->fncols_new + 2 ; if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, 1)) { DEBUGm4 (("out of memory: extend front\n")) ; return (FALSE) ; } } fnr_curr = Work->fnr_curr ; fnc_curr = Work->fnc_curr ; ASSERT (Work->fnrows_new + 1 <= fnr_curr) ; ASSERT (Work->fncols_new + 1 <= fnc_curr) ; ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ Frows = Work->Frows ; Frpos = Work->Frpos ; Fcols = Work->Fcols ; Fcpos = Work->Fcpos ; fnrows = Work->fnrows ; fncols = Work->fncols ; rrdeg = Work->rrdeg ; ccdeg = Work->ccdeg ; /* scan starts at the first new column in Fcols */ /* also scan the pivot column if it was not in the front */ Work->fscan_col = fncols ; Work->NewCols = Fcols ; /* scan1 starts at the first new row in Frows */ /* also scan the pivot row if it was not in the front */ Work->fscan_row = fnrows ; Work->NewRows = Frows ; /* ---------------------------------------------------------------------- */ /* extend row pattern of the front with the new pivot column */ /* ---------------------------------------------------------------------- */ fnrows_extended = fnrows ; fncols_extended = fncols ; #ifndef NDEBUG DEBUG2 (("Pivot col, before extension: "ID"\n", fnrows)) ; for (i = 0 ; i < fnrows ; i++) { DEBUG2 ((" "ID": row "ID"\n", i, Frows [i])) ; ASSERT (Frpos [Frows [i]] == i) ; } DEBUG2 (("Extending pivot column: pivcol_in_front: "ID"\n", Work->pivcol_in_front)) ; #endif Fl = Work->Flblock + fnpiv * fnr_curr ; if (Work->pivcol_in_front) { /* extended pattern and position already in Frows, Frpos. Values above * the diagonal are already in LU block. Values on and below the * diagonal are in Wy [0 .. fnrows_extended-1]. Copy into the L * block. */ fnrows_extended += ccdeg ; Wy = Work->Wy ; for (i = 0 ; i < fnrows_extended ; i++) { Fl [i] = Wy [i] ; #ifndef NDEBUG row = Frows [i] ; DEBUG2 ((" "ID": row "ID" ", i, row)) ; EDEBUG2 (Fl [i]) ; if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ; DEBUG2 (("\n")) ; if (i == fnrows - 1) DEBUG2 ((" :::::::\n")) ; ASSERT (row >= 0 && row < Work->n_row) ; ASSERT (Frpos [row] == i) ; #endif } } else { /* extended pattern,values is in (Wm,Wx), not yet in the front */ Entry *F ; Fu = Work->Flublock + fnpiv * Work->nb ; Wm = Work->Wm ; Wx = Work->Wx ; F = Fu ; for (i = 0 ; i < fnpiv ; i++) { CLEAR_AND_INCREMENT (F) ; } F = Fl ; for (i = 0 ; i < fnrows ; i++) { CLEAR_AND_INCREMENT (F) ; } for (i = 0 ; i < ccdeg ; i++) { row = Wm [i] ; #ifndef NDEBUG DEBUG2 ((" "ID": row "ID" (ext) ", fnrows_extended, row)) ; EDEBUG2 (Wx [i]) ; if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ; DEBUG2 (("\n")) ; ASSERT (row >= 0 && row < Work->n_row) ; #endif pos = Frpos [row] ; if (pos < 0) { pos = fnrows_extended++ ; Frows [pos] = row ; Frpos [row] = pos ; } Fl [pos] = Wx [i] ; } } ASSERT (fnrows_extended <= fnr_curr) ; /* ---------------------------------------------------------------------- */ /* extend the column pattern of the front with the new pivot row */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG6 (("Pivot row, before extension: "ID"\n", fncols)) ; for (j = 0 ; j < fncols ; j++) { DEBUG7 ((" "ID": col "ID"\n", j, Fcols [j])) ; ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ; } DEBUG6 (("Extending pivot row:\n")) ; #endif if (Work->pivrow_in_front) { if (Work->pivcol_in_front) { ASSERT (Fcols == Work->Wrow) ; for (j = fncols ; j < rrdeg ; j++) { #ifndef NDEBUG col = Fcols [j] ; DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ; ASSERT (col != Work->pivcol) ; ASSERT (col >= 0 && col < Work->n_col) ; ASSERT (Fcpos [col] < 0) ; #endif Fcpos [Fcols [j]] = j * fnr_curr ; } } else { /* OUT-IN option: pivcol not in front, but pivrow is in front */ Wrow = Work->Wrow ; ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ; if (Wrow == Fcols) { /* Wrow and Fcols are equivalenced */ for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ; ASSERT (Fcpos [col] < 0) ; /* Fcols [j] = col ; not needed */ Fcpos [col] = j * fnr_curr ; } } else { for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ; ASSERT (Fcpos [col] < 0) ; Fcols [j] = col ; Fcpos [col] = j * fnr_curr ; } } } fncols_extended = rrdeg ; } else { ASSERT (Fcols != Work->Wrow) ; Wrow = Work->Wrow ; for (j = 0 ; j < rrdeg ; j++) { col = Wrow [j] ; ASSERT (col >= 0 && col < Work->n_col) ; if (Fcpos [col] < 0) { DEBUG2 ((" col:: "ID" (ext)\n", col)) ; Fcols [fncols_extended] = col ; Fcpos [col] = fncols_extended * fnr_curr ; fncols_extended++ ; } } } /* ---------------------------------------------------------------------- */ /* pivot row and column have been extended */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG ASSERT (fncols_extended <= fnc_curr) ; ASSERT (fnrows_extended <= fnr_curr) ; DEBUG6 (("Pivot col, after ext: "ID" "ID"\n", fnrows,fnrows_extended)) ; for (i = 0 ; i < fnrows_extended ; i++) { row = Frows [i] ; DEBUG7 ((" "ID": row "ID" pos "ID" old: %d", i, row, Frpos [row], i < fnrows)) ; if (row == Work->pivrow ) DEBUG7 ((" <-- pivrow")) ; DEBUG7 (("\n")) ; ASSERT (Frpos [Frows [i]] == i) ; } DEBUG6 (("Pivot row position: "ID"\n", Frpos [Work->pivrow])) ; ASSERT (Frpos [Work->pivrow] >= 0) ; ASSERT (Frpos [Work->pivrow] < fnrows_extended) ; DEBUG6 (("Pivot row, after ext: "ID" "ID"\n", fncols,fncols_extended)) ; for (j = 0 ; j < fncols_extended ; j++) { col = Fcols [j] ; DEBUG7 ((" "ID": col "ID" pos "ID" old: %d", j, col, Fcpos [col], j < fncols)) ; if (col == Work->pivcol ) DEBUG7 ((" <-- pivcol")) ; DEBUG7 (("\n")) ; ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ; } DEBUG6 (("Pivot col position: "ID"\n", Fcpos [Work->pivcol])) ; ASSERT (Fcpos [Work->pivcol] >= 0) ; ASSERT (Fcpos [Work->pivcol] < fncols_extended * fnr_curr) ; #endif /* ---------------------------------------------------------------------- */ /* Zero the newly extended frontal matrix */ /* ---------------------------------------------------------------------- */ zero_front (Work->Flblock, Work->Fublock, Work->Fcblock, fnrows, fncols, fnr_curr, fnc_curr, fnpiv, fnrows_extended, fncols_extended) ; /* ---------------------------------------------------------------------- */ /* finalize extended row and column pattern of the frontal matrix */ /* ---------------------------------------------------------------------- */ Work->fnrows = fnrows_extended ; Work->fncols = fncols_extended ; ASSERT (fnrows_extended == Work->fnrows_new + 1) ; ASSERT (fncols_extended == Work->fncols_new + 1) ; return (TRUE) ; }