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) ; }
GLOBAL Int UMF_init_front ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int i, j, fnr_curr, row, col, *Frows, *Fcols, *Fcpos, *Frpos, fncols, fnrows, *Wrow, fnr2, fnc2, rrdeg, ccdeg, *Wm, fnrows_extended ; Entry *Fcblock, *Fl, *Wy, *Wx ; /* ---------------------------------------------------------------------- */ /* get current frontal matrix and check for frontal growth */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG0 (("INIT FRONT\n")) ; DEBUG1 (("CURR before init:\n")) ; UMF_dump_current_front (Numeric, Work, FALSE) ; #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, Work->pivrow_in_front ? 2 : 0)) { /* :: out of memory in umf_init_front :: */ DEBUGm4 (("out of memory: init front\n")) ; return (FALSE) ; } } #ifndef NDEBUG DEBUG1 (("CURR after grow:\n")) ; UMF_dump_current_front (Numeric, Work, FALSE) ; DEBUG1 (("fnrows new "ID" fncols new "ID"\n", Work->fnrows_new, Work->fncols_new)) ; #endif ASSERT (Work->fnpiv == 0) ; fnr_curr = Work->fnr_curr ; ASSERT (Work->fnrows_new + 1 <= fnr_curr) ; ASSERT (Work->fncols_new + 1 <= Work->fnc_curr) ; ASSERT (fnr_curr >= 0) ; ASSERT (fnr_curr % 2 == 1) ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ /* current front is defined by pivot row and column */ Frows = Work->Frows ; Fcols = Work->Fcols ; Frpos = Work->Frpos ; Fcpos = Work->Fcpos ; Work->fnzeros = 0 ; ccdeg = Work->ccdeg ; rrdeg = Work->rrdeg ; fnrows = Work->fnrows ; fncols = Work->fncols ; /* if both pivrow and pivcol are in front, then we extend the old one */ /* in UMF_extend_front, rather than starting a new one here. */ ASSERT (! (Work->pivrow_in_front && Work->pivcol_in_front)) ; /* ---------------------------------------------------------------------- */ /* place pivot column pattern in frontal matrix */ /* ---------------------------------------------------------------------- */ Fl = Work->Flblock ; if (Work->pivcol_in_front) { /* Append the pivot column extension. * Note that all we need to do is increment the size, since the * candidate pivot column pattern is already in place in * Frows [0 ... fnrows-1] (the old pattern), and * Frows [fnrows ... fnrows + Work->ccdeg - 1] (the new * pattern). Frpos is also properly defined. */ /* make a list of the new rows to scan */ Work->fscan_row = fnrows ; /* only scan the new rows */ Work->NewRows = Work->Wrp ; Wy = Work->Wy ; for (i = 0 ; i < fnrows ; i++) { Fl [i] = Wy [i] ; } fnrows_extended = fnrows + ccdeg ; for (i = fnrows ; i < fnrows_extended ; i++) { Fl [i] = Wy [i] ; /* flip the row, since Wrp must be < 0 */ row = Frows [i] ; Work->NewRows [i] = FLIP (row) ; } fnrows = fnrows_extended ; } else { /* this is a completely new column */ Work->fscan_row = 0 ; /* scan all the rows */ Work->NewRows = Frows ; Wm = Work->Wm ; Wx = Work->Wx ; for (i = 0 ; i < ccdeg ; i++) { Fl [i] = Wx [i] ; row = Wm [i] ; Frows [i] = row ; Frpos [row] = i ; } fnrows = ccdeg ; } Work->fnrows = fnrows ; #ifndef NDEBUG DEBUG3 (("New Pivot col "ID" now in front, length "ID"\n", Work->pivcol, fnrows)) ; for (i = 0 ; i < fnrows ; i++) { DEBUG4 ((" "ID": row "ID"\n", i, Frows [i])) ; ASSERT (Frpos [Frows [i]] == i) ; } #endif /* ---------------------------------------------------------------------- */ /* place pivot row pattern in frontal matrix */ /* ---------------------------------------------------------------------- */ Wrow = Work->Wrow ; if (Work->pivrow_in_front) { /* append the pivot row extension */ Work->fscan_col = fncols ; /* only scan the new columns */ Work->NewCols = Work->Wp ; #ifndef NDEBUG for (j = 0 ; j < fncols ; j++) { col = Fcols [j] ; ASSERT (col >= 0 && col < Work->n_col) ; ASSERT (Fcpos [col] == j * fnr_curr) ; } #endif /* Wrow == Fcol for the IN_IN case, and for the OUT_IN case when * the pivrow [IN][IN] happens to be the same as pivrow [OUT][IN]. * See UMF_local_search for more details. */ ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ; if (Wrow == Fcols) { for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; /* Fcols [j] = col ; not needed */ /* flip the col index, since Wp must be < 0 */ Work->NewCols [j] = FLIP (col) ; Fcpos [col] = j * fnr_curr ; } } else { for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; Fcols [j] = col ; /* flip the col index, since Wp must be < 0 */ Work->NewCols [j] = FLIP (col) ; Fcpos [col] = j * fnr_curr ; } } } else { /* this is a completely new row */ Work->fscan_col = 0 ; /* scan all the columns */ Work->NewCols = Fcols ; for (j = 0 ; j < rrdeg ; j++) { col = Wrow [j] ; Fcols [j] = col ; Fcpos [col] = j * fnr_curr ; } } DEBUGm1 (("rrdeg "ID" fncols "ID"\n", rrdeg, fncols)) ; fncols = rrdeg ; Work->fncols = fncols ; /* ---------------------------------------------------------------------- */ /* clear the frontal matrix */ /* ---------------------------------------------------------------------- */ ASSERT (fnrows == Work->fnrows_new + 1) ; ASSERT (fncols == Work->fncols_new + 1) ; Fcblock = Work->Fcblock ; ASSERT (Fcblock != (Entry *) NULL) ; zero_init_front (fncols, fnrows, Fcblock, fnr_curr) ; #ifndef NDEBUG DEBUG3 (("New Pivot row "ID" now in front, length "ID" fnr_curr "ID"\n", Work->pivrow, fncols, fnr_curr)) ; for (j = 0 ; j < fncols ; j++) { DEBUG4 (("col "ID" position "ID"\n", j, Fcols [j])) ; ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ; } #endif /* ---------------------------------------------------------------------- */ /* current workspace usage: */ /* ---------------------------------------------------------------------- */ /* Fcblock [0..fnr_curr-1, 0..fnc_curr-1]: space for the new frontal * matrix. Fcblock (i,j) is located at Fcblock [i+j*fnr_curr] */ return (TRUE) ; }
GLOBAL Int UMF_start_front /* returns TRUE if successful, FALSE otherwise */ ( Int chain, NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) { Int fnrows_max, fncols_max, fnr2, fnc2, fsize, fcurr_size, maxfrsize, overflow, nb, f, cdeg ; double maxbytes ; nb = Symbolic->nb ; fnrows_max = Symbolic->Chain_maxrows [chain] ; fncols_max = Symbolic->Chain_maxcols [chain] ; DEBUGm2 (("Start Front for chain "ID". fnrows_max "ID" fncols_max "ID"\n", chain, fnrows_max, fncols_max)) ; Work->fnrows_max = fnrows_max ; Work->fncols_max = fncols_max ; Work->any_skip = FALSE ; maxbytes = sizeof (Entry) * (double) (fnrows_max + nb) * (double) (fncols_max + nb) ; fcurr_size = Work->fcurr_size ; if (Symbolic->prefer_diagonal) { /* Get a rough upper bound on the degree of the first pivot column in * this front. Note that Col_degree is not maintained if diagonal * pivoting is preferred. For most matrices, the first pivot column * of the first frontal matrix of a new chain has only one tuple in * it anyway, so this bound is exact in that case. */ Int col, tpi, e, *E, *Col_tuples, *Col_tlen, *Cols ; Tuple *tp, *tpend ; Unit *Memory, *p ; Element *ep ; E = Work->E ; Memory = Numeric->Memory ; Col_tuples = Numeric->Lip ; Col_tlen = Numeric->Lilen ; col = Work->nextcand ; tpi = Col_tuples [col] ; tp = (Tuple *) Memory + tpi ; tpend = tp + Col_tlen [col] ; cdeg = 0 ; DEBUGm3 (("\n=============== start front: col "ID" tlen "ID"\n", col, Col_tlen [col])) ; for ( ; tp < tpend ; tp++) { DEBUG1 (("Tuple ("ID","ID")\n", tp->e, tp->f)) ; e = tp->e ; if (!E [e]) continue ; f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; if (Cols [f] == EMPTY) continue ; DEBUG1 ((" nrowsleft "ID"\n", ep->nrowsleft)) ; cdeg += ep->nrowsleft ; } #ifndef NDEBUG DEBUGm3 (("start front cdeg: "ID" col "ID"\n", cdeg, col)) ; UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; #endif /* cdeg is now the rough upper bound on the degree of the next pivot * column. */ /* If AMD was called, we know the maximum number of nonzeros in any * column of L. Use this as an upper bound for cdeg, but add 2 to * account for a small amount of off-diagonal pivoting. */ if (Symbolic->amd_dmax > 0) { cdeg = MIN (cdeg, Symbolic->amd_dmax) ; } /* Increase it to account for larger columns later on. * Also ensure that it's larger than zero. */ cdeg += 2 ; /* cdeg cannot be larger than fnrows_max */ cdeg = MIN (cdeg, fnrows_max) ; } else { /* don't do the above cdeg computation */ cdeg = 0 ; } DEBUGm2 (("fnrows max "ID" fncols_max "ID"\n", fnrows_max, fncols_max)) ; /* the current frontal matrix is empty */ ASSERT (Work->fnrows == 0 && Work->fncols == 0 && Work->fnpiv == 0) ; /* maximum row dimension is always odd, to avoid bad cache effects */ ASSERT (fnrows_max >= 0) ; ASSERT (fnrows_max % 2 == 1) ; /* ---------------------------------------------------------------------- * allocate working array for current frontal matrix: * minimum size: 1-by-1 * maximum size: fnrows_max-by-fncols_max * desired size: * * if Numeric->front_alloc_init >= 0: * * for unsymmetric matrices: * Numeric->front_alloc_init * (fnrows_max-by-fncols_max) * * for symmetric matrices (diagonal pivoting preference, actually): * Numeric->front_alloc_init * (fnrows_max-by-fncols_max), or * cdeg*cdeg, whichever is smaller. * * if Numeric->front_alloc_init < 0: * allocate a front of size -Numeric->front_alloc_init. * * Allocate the whole thing if it's small (less than 2*nb^2). Make sure the * leading dimension of the frontal matrix is odd. * * Also allocate the nb-by-nb LU block, the dr-by-nb L block, and the * nb-by-dc U block. * ---------------------------------------------------------------------- */ /* get the maximum front size, avoiding integer overflow */ overflow = INT_OVERFLOW (maxbytes) ; if (overflow) { /* :: int overflow, max front size :: */ maxfrsize = Int_MAX / sizeof (Entry) ; } else { maxfrsize = (fnrows_max + nb) * (fncols_max + nb) ; } ASSERT (!INT_OVERFLOW ((double) maxfrsize * sizeof (Entry))) ; if (Numeric->front_alloc_init < 0) { /* allocate a front of -Numeric->front_alloc_init entries */ fsize = -Numeric->front_alloc_init ; fsize = MAX (1, fsize) ; } else { if (INT_OVERFLOW (Numeric->front_alloc_init * maxbytes)) { /* :: int overflow, requested front size :: */ fsize = Int_MAX / sizeof (Entry) ; } else { fsize = Numeric->front_alloc_init * maxfrsize ; } if (cdeg > 0) { /* diagonal pivoting is in use. cdeg was computed above */ Int fsize2 ; /* add the L and U blocks */ cdeg += nb ; if (INT_OVERFLOW (((double) cdeg * (double) cdeg) * sizeof (Entry))) { /* :: int overflow, symmetric front size :: */ fsize2 = Int_MAX / sizeof (Entry) ; } else { fsize2 = MAX (cdeg * cdeg, fcurr_size) ; } fsize = MIN (fsize, fsize2) ; } } fsize = MAX (fsize, 2*nb*nb) ; /* fsize and maxfrsize are now safe from integer overflow. They both * include the size of the pivot blocks. */ ASSERT (!INT_OVERFLOW ((double) fsize * sizeof (Entry))) ; Work->fnrows_new = 0 ; Work->fncols_new = 0 ; /* desired size is fnr2-by-fnc2 (includes L and U blocks): */ DEBUGm2 ((" fsize "ID" fcurr_size "ID"\n", fsize, fcurr_size)) ; DEBUGm2 ((" maxfrsize "ID" fnr_curr "ID" fnc_curr "ID"\n", maxfrsize, Work->fnr_curr, Work->fnc_curr)) ; if (fsize >= maxfrsize && !overflow) { /* max working array is small, allocate all of it */ fnr2 = fnrows_max + nb ; fnc2 = fncols_max + nb ; fsize = maxfrsize ; DEBUGm1 ((" sufficient for ("ID"+"ID")-by-("ID"+"ID")\n", fnrows_max, nb, fncols_max, nb)) ; } else { /* allocate a smaller working array */ if (fnrows_max <= fncols_max) { fnr2 = (Int) sqrt ((double) fsize) ; /* make sure fnr2 is odd */ fnr2 = MAX (fnr2, 1) ; if (fnr2 % 2 == 0) fnr2++ ; fnr2 = MIN (fnr2, fnrows_max + nb) ; fnc2 = fsize / fnr2 ; } else { fnc2 = (Int) sqrt ((double) fsize) ; fnc2 = MIN (fnc2, fncols_max + nb) ; fnr2 = fsize / fnc2 ; /* make sure fnr2 is odd */ fnr2 = MAX (fnr2, 1) ; if (fnr2 % 2 == 0) { fnr2++ ; fnc2 = fsize / fnr2 ; } } DEBUGm1 ((" smaller "ID"-by-"ID"\n", fnr2, fnc2)) ; } fnr2 = MIN (fnr2, fnrows_max + nb) ; fnc2 = MIN (fnc2, fncols_max + nb) ; ASSERT (fnr2 % 2 == 1) ; ASSERT (fnr2 * fnc2 <= fsize) ; fnr2 -= nb ; fnc2 -= nb ; ASSERT (fnr2 >= 0) ; ASSERT (fnc2 >= 0) ; if (fsize > fcurr_size) { DEBUGm1 ((" Grow front \n")) ; Work->do_grow = TRUE ; if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, -1)) { /* since the minimum front size is 1-by-1, it would be nearly * impossible to run out of memory here. */ DEBUGm4 (("out of memory: start front\n")) ; return (FALSE) ; } } else { /* use the existing front */ DEBUGm1 ((" existing front ok\n")) ; Work->fnr_curr = fnr2 ; Work->fnc_curr = fnc2 ; Work->Flblock = Work->Flublock + nb * nb ; Work->Fublock = Work->Flblock + nb * fnr2 ; Work->Fcblock = Work->Fublock + nb * fnc2 ; } 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) ; return (TRUE) ; }