Mercurial > octave-nkf
diff liboctave/UMFPACK/UMFPACK/Source/umf_kernel_init.c @ 5164:57077d0ddc8e
[project @ 2005-02-25 19:55:24 by jwe]
author | jwe |
---|---|
date | Fri, 25 Feb 2005 19:55:28 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/liboctave/UMFPACK/UMFPACK/Source/umf_kernel_init.c Fri Feb 25 19:55:28 2005 +0000 @@ -0,0 +1,1056 @@ +/* ========================================================================== */ +/* === UMF_kernel_init ====================================================== */ +/* ========================================================================== */ + +/* -------------------------------------------------------------------------- */ +/* UMFPACK Version 4.4, Copyright (c) 2005 by Timothy A. Davis. CISE Dept, */ +/* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ +/* web: http://www.cise.ufl.edu/research/sparse/umfpack */ +/* -------------------------------------------------------------------------- */ + +/* + Initialize the kernel: scale the matrix, load the initial elements, and + build the tuple lists. + + Returns TRUE if successful, FALSE if out of memory or if the pattern has + changed since UMFPACK_*symbolic. UMFPACK_numeric allocates at least enough + space for UMF_kernel_init to succeed; otherwise it does not call + UMF_kernel_init. So an out-of-memory condition means that the pattern must + have gotten larger. +*/ + +#include "umf_internal.h" +#include "umf_tuple_lengths.h" +#include "umf_build_tuples.h" +#include "umf_mem_init_memoryspace.h" +#include "umf_mem_alloc_element.h" +#include "umf_mem_alloc_head_block.h" +#include "umf_mem_alloc_tail_block.h" +#include "umf_mem_free_tail_block.h" +#include "umf_scale.h" + +/* ========================================================================== */ +/* === packsp =============================================================== */ +/* ========================================================================== */ + +/* remove zero or small entries from a column of L or a row of U */ + +PRIVATE Int packsp /* returns new value of pnew */ +( + Int pnew, /* index into Memory of next free space */ + Int *p_p, /* ptr to index of old pattern in Memory on input, + new pattern on output */ + Int *p_len, /* ptr to length of old pattern on input, + new pattern on output */ + Int drop, /* TRUE if small nonzero entries are to be dropped */ + double droptol, /* the drop tolerance */ + Unit *Memory /* contains the sparse vector on input and output */ +) +{ + Entry x ; + double s ; + Entry *Bx, *Bx2 ; + Int p, i, len, len_new, *Bi, *Bi2 ; + + /* get the pointers to the sparse vector, and its length */ + p = *p_p ; + len = *p_len ; + Bi = (Int *) (Memory + p) ; p += UNITS (Int, len) ; + Bx = (Entry *) (Memory + p) ; p += UNITS (Entry, len) ; + DEBUGm4 ((" p "ID" len "ID" pnew "ID"\n", p, len, pnew)) ; + + /* the vector resides in Bi [0..len-1] and Bx [0..len-1] */ + + /* first, compact the vector in place */ + len_new = 0 ; + for (p = 0 ; p < len ; p++) + { + i = Bi [p] ; + x = Bx [p] ; + DEBUGm4 ((" old vector: i "ID" value: ", i)) ; + EDEBUGk (-4, x) ; + DEBUGm4 (("\n")) ; + ASSERT (i >= 0) ; + /* skip if zero or below drop tolerance */ + if (IS_ZERO (x)) continue ; + if (drop) + { + APPROX_ABS (s, x) ; + if (s <= droptol) continue ; + } + /* store the value back into the vector */ + if (len_new != p) + { + Bi [len_new] = i ; + Bx [len_new] = x ; + } + len_new++ ; + } + ASSERT (len_new <= len) ; + + /* the vector is now in Bi [0..len_new-1] and Bx [0..len_new-1] */ + +#ifndef NDEBUG + for (p = 0 ; p < len_new ; p++) + { + DEBUGm4 ((" new vector: i "ID" value: ", Bi [p])) ; + EDEBUGk (-4, Bx [p]) ; + DEBUGm4 (("\n")) ; + ASSERT (Bi [p] >= 0) ; + } +#endif + + /* allocate new space for the compacted vector */ + *p_p = pnew ; + *p_len = len_new ; + Bi2 = (Int *) (Memory + pnew) ; pnew += UNITS (Int, len_new) ; + Bx2 = (Entry *) (Memory + pnew) ; pnew += UNITS (Entry, len_new) ; + DEBUGm4 ((" pnew "ID" len_new "ID"\n", pnew, len_new)) ; + + /* shift the vector upwards, into its new space */ + for (p = 0 ; p < len_new ; p++) + { + Bi2 [p] = Bi [p] ; + } + for (p = 0 ; p < len_new ; p++) + { + Bx2 [p] = Bx [p] ; + } + +#ifndef NDEBUG + for (p = 0 ; p < len_new ; p++) + { + DEBUGm4 ((" packed vec: i "ID" value: ", Bi2 [p])) ; + EDEBUGk (-4, Bx2 [p]) ; + DEBUGm4 (("\n")) ; + ASSERT (Bi2 [p] >= 0) ; + } +#endif + + /* return the pointer to the space just after the new vector */ + return (pnew) ; +} + + +/* ========================================================================== */ +/* === UMF_kernel_init ====================================================== */ +/* ========================================================================== */ + +GLOBAL Int UMF_kernel_init +( + const Int Ap [ ], /* user's input matrix (not modified) */ + const Int Ai [ ], + const double Ax [ ], +#ifdef COMPLEX + const double Az [ ], +#endif + NumericType *Numeric, + WorkType *Work, + SymbolicType *Symbolic +) +{ + /* ---------------------------------------------------------------------- */ + /* local variables */ + /* ---------------------------------------------------------------------- */ + + Entry x, pivot_value ; + double unused = 0, rsmin, rsmax, rs, droptol ; + Entry *D, *C, *Lval, **Rpx ; + double *Rs ; + Int row, k, oldcol, size, e, p1, p2, p, nz, *Rows, *Cols, *E, i, *Upos, + *Lpos, n_row, n_col, *Wp, *Cperm_init, *Frpos, *Fcpos, *Row_degree, nn, + *Row_tlen, *Col_degree, *Col_tlen, oldrow, newrow, ilast, *Wrp, + *Rperm_init, col, n_inner, prefer_diagonal, *Diagonal_map, nempty, + *Diagonal_imap, fixQ, rdeg, cdeg, nempty_col, *Esize, esize, pnew, + *Lip, *Uip, *Lilen, *Uilen, llen, pa, *Cdeg, *Rdeg, n1, clen, do_scale, + lnz, unz, lip, uip, k1, *Rperm, *Cperm, pivcol, *Li, lilen, drop, + **Rpi, nempty_row, dense_row_threshold, empty_elements, rpi, rpx ; + Element *ep ; + Unit *Memory ; +#ifdef COMPLEX + Int split = SPLIT (Az) ; +#endif +#ifndef NRECIPROCAL + Int do_recip = FALSE ; +#endif + + /* ---------------------------------------------------------------------- */ + /* get parameters */ + /* ---------------------------------------------------------------------- */ + + DEBUG0 (("KERNEL INIT\n")) ; + + n_row = Symbolic->n_row ; + n_col = Symbolic->n_col ; + nn = MAX (n_row, n_col) ; + n_inner = MIN (n_row, n_col) ; + nempty_col = Symbolic->nempty_col ; + nempty_row = Symbolic->nempty_row ; + nempty = MIN (nempty_row, nempty_col) ; + ASSERT (n_row > 0 && n_col > 0) ; + Cperm_init = Symbolic->Cperm_init ; + Rperm_init = Symbolic->Rperm_init ; + Cdeg = Symbolic->Cdeg ; + Rdeg = Symbolic->Rdeg ; + n1 = Symbolic->n1 ; + dense_row_threshold = Symbolic->dense_row_threshold ; + DEBUG0 (("Singletons: "ID"\n", n1)) ; + Work->nforced = 0 ; + Work->ndiscard = 0 ; + Work->noff_diagonal = 0 ; + + nz = Ap [n_col] ; + if (nz < 0 || Ap [0] != 0 || nz != Symbolic->nz) + { + DEBUGm4 (("nz or Ap [0] bad\n")) ; + return (FALSE) ; /* pattern changed */ + } + + prefer_diagonal = Symbolic->prefer_diagonal ; + Diagonal_map = Work->Diagonal_map ; + Diagonal_imap = Work->Diagonal_imap ; + + /* ---------------------------------------------------------------------- */ + /* initialize the Numeric->Memory space for LU, elements, and tuples */ + /* ---------------------------------------------------------------------- */ + + UMF_mem_init_memoryspace (Numeric) ; + DEBUG1 (("Kernel init head usage, before allocs: "ID"\n", Numeric->ihead)) ; + + /* ---------------------------------------------------------------------- */ + /* initialize the Work and Numeric objects */ + /* ---------------------------------------------------------------------- */ + + /* current front is empty */ + Work->fnpiv = 0 ; + Work->fncols = 0 ; + Work->fnrows = 0 ; + Work->fncols_max = 0 ; + Work->fnrows_max = 0 ; + Work->fnzeros = 0 ; + Work->fcurr_size = 0 ; + Work->fnr_curr = 0 ; + Work->fnc_curr = 0 ; + + Work->nz = nz ; + Work->prior_element = EMPTY ; + Work->ulen = 0 ; + Work->llen = 0 ; + Work->npiv = n1 ; + Work->frontid = 0 ; + Work->nextcand = n1 ; + + Memory = Numeric->Memory ; + Rperm = Numeric->Rperm ; + Cperm = Numeric->Cperm ; + Row_degree = Numeric->Rperm ; + Col_degree = Numeric->Cperm ; + /* Row_tuples = Numeric->Uip ; not needed */ + Row_tlen = Numeric->Uilen ; + /* Col_tuples = Numeric->Lip ; not needed */ + Col_tlen = Numeric->Lilen ; + + Lip = Numeric->Lip ; + Uip = Numeric->Uip ; + Lilen = Numeric->Lilen ; + Uilen = Numeric->Uilen ; + + Frpos = Work->Frpos ; + Fcpos = Work->Fcpos ; + Wp = Work->Wp ; + Wrp = Work->Wrp ; + + D = Numeric->D ; + Upos = Numeric->Upos ; + Lpos = Numeric->Lpos ; + for (k = 0 ; k < n_inner ; k++) + { + CLEAR (D [k]) ; + } + + Rs = Numeric->Rs ; + + for (row = 0 ; row <= n_row ; row++) + { + Lpos [row] = EMPTY ; + /* Row_tuples [row] = 0 ; set in UMF_build_tuples */ + /* Row_degree [row] = 0 ; initialized below */ + Row_tlen [row] = 0 ; + /* Frpos [row] = EMPTY ; do this later */ + } + + for (col = 0 ; col <= n_col ; col++) + { + Upos [col] = EMPTY ; + /* Col_tuples [col] = 0 ; set in UMF_build_tuples */ + /* Col_degree [col] = 0 ; initialized below */ + Col_tlen [col] = 0 ; + Fcpos [col] = EMPTY ; + Wrp [col] = 0 ; + } + Work->Wrpflag = 1 ; + + /* When cleared, Wp [0..nn] is < 0 */ + for (i = 0 ; i <= nn ; i++) + { + Wp [i] = EMPTY ; + } + /* In col search, Wp [row] is set to a position, which is >= 0. */ + + /* When cleared, Wrp [0..n_col] is < Wrpflag */ + /* In row search, Wrp [col] is set to Wrpflag. */ + + /* no need to initialize Wm, Wio, Woi, and Woo */ + + /* clear the external degree counters */ + Work->cdeg0 = 1 ; + Work->rdeg0 = 1 ; + + fixQ = Symbolic->fixQ ; + + E = Work->E ; + + Numeric->n_row = n_row ; + Numeric->n_col = n_col ; + Numeric->npiv = 0 ; + Numeric->nnzpiv = 0 ; + Numeric->min_udiag = 0.0 ; + Numeric->max_udiag = 0.0 ; + Numeric->rcond = 0.0 ; + Numeric->isize = 0 ; + Numeric->nLentries = 0 ; + Numeric->nUentries = 0 ; + Numeric->lnz = 0 ; + Numeric->unz = 0 ; + Numeric->all_lnz = 0 ; + Numeric->all_unz = 0 ; + Numeric->maxfrsize = 0 ; + Numeric->maxnrows = 0 ; + Numeric->maxncols = 0 ; + Numeric->flops = 0. ; + Numeric->n1 = n1 ; + droptol = Numeric->droptol ; + drop = (droptol > 0) ; + + /* ---------------------------------------------------------------------- */ + /* compute the scale factors, if requested, and check the input matrix */ + /* ---------------------------------------------------------------------- */ + + /* UMFPACK_SCALE_SUM: Rs [i] = sum of the absolute values in row i. + * UMFPACK_SCALE_MAX: Rs [i] = max of the absolute values in row i. + * + * If A is complex, an approximate abs is used (|xreal| + |ximag|). + * + * If min (Rs [0..n_row]) >= RECIPROCAL_TOLERANCE, then the scale + * factors are inverted, and the rows of A are multiplied by the scale + * factors. Otherwise, the rows are divided by the scale factors. If + * NRECIPROCAL is defined, then the rows are always divided by the scale + * factors. + * + * For MATLAB (either built-in routine or mexFunction), or for gcc, + * the rows are always divided by the scale factors. + */ + + do_scale = (Numeric->scale != UMFPACK_SCALE_NONE) ; + + if (do_scale) + { + int do_max = Numeric->scale == UMFPACK_SCALE_MAX ; + for (row = 0 ; row < n_row ; row++) + { + Rs [row] = 0.0 ; + } + for (col = 0 ; col < n_col ; col++) + { + ilast = EMPTY ; + p1 = Ap [col] ; + p2 = Ap [col+1] ; + if (p1 > p2) + { + /* invalid matrix */ + DEBUGm4 (("invalid matrix (Ap)\n")) ; + return (FALSE) ; + } + for (p = p1 ; p < p2 ; p++) + { + Entry aij ; + double value ; + row = Ai [p] ; + if (row <= ilast || row >= n_row) + { + /* invalid matrix, columns must be sorted, no duplicates */ + DEBUGm4 (("invalid matrix (Ai)\n")) ; + return (FALSE) ; + } + ASSIGN (aij, Ax, Az, p, split) ; + APPROX_ABS (value, aij) ; + rs = Rs [row] ; + if (!SCALAR_IS_NAN (rs)) + { + if (SCALAR_IS_NAN (value)) + { + /* if any entry in the row is NaN, then the scale factor + * is NaN too (for now) and then set to 1.0 below */ + Rs [row] = value ; + } + else if (do_max) + { + Rs [row] = MAX (rs, value) ; + } + else + { + Rs [row] += value ; + } + } + DEBUG4 (("i "ID" j "ID" value %g, Rs[i]: %g\n", + row, col, value, Rs[row])) ; + ilast = row ; + } + } + DEBUG2 (("Rs[0] = %30.20e\n", Rs [0])) ; + for (row = 0 ; row < n_row ; row++) + { + rs = Rs [row] ; + if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs)) + { + /* don't scale a completely zero row, or one with NaN's */ + Rs [row] = 1.0 ; + } + } + rsmin = Rs [0] ; + rsmax = Rs [0] ; + for (row = 0 ; row < n_row ; row++) + { + DEBUG2 (("sum %30.20e ", Rs [row])) ; + rsmin = MIN (rsmin, Rs [row]) ; + rsmax = MAX (rsmax, Rs [row]) ; + DEBUG2 (("Rs["ID"] = %30.20e\n", row, Rs [row])) ; + } +#ifndef NRECIPROCAL + /* multiply by the reciprocal if Rs is not too small */ + do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ; + if (do_recip) + { + /* invert the scale factors */ + for (row = 0 ; row < n_row ; row++) + { + Rs [row] = 1.0 / Rs [row] ; + } + } +#endif + } + else + { + /* no scaling, rsmin and rsmax not computed */ + rsmin = -1 ; + rsmax = -1 ; +#ifndef NRECIPROCAL + do_recip = FALSE ; +#endif + /* check the input matrix */ + if (!AMD_valid (n_row, n_col, Ap, Ai)) + { + /* matrix is invalid */ + return (FALSE) ; + } + } + + Numeric->rsmin = rsmin ; + Numeric->rsmax = rsmax ; +#ifndef NRECIPROCAL + Numeric->do_recip = do_recip ; +#else + Numeric->do_recip = FALSE ; +#endif + + /* ---------------------------------------------------------------------- */ + /* construct the inverse row Rperm_init permutation (use Frpos as temp) */ + /* ---------------------------------------------------------------------- */ + + DEBUG3 (("\n\n===================LOAD_MATRIX:\n")) ; + + for (newrow = 0 ; newrow < n_row ; newrow++) + { + oldrow = Rperm_init [newrow] ; + ASSERT (oldrow >= 0 && oldrow < n_row) ; + Frpos [oldrow] = newrow ; + } + + /* ---------------------------------------------------------------------- */ + /* construct the diagonal imap if doing symmetric pivoting */ + /* ---------------------------------------------------------------------- */ + + if (prefer_diagonal) + { + ASSERT (n_row == n_col) ; + ASSERT (nempty_col == Symbolic->nempty_row) ; + ASSERT (nempty_col == nempty) ; + for (i = 0 ; i < nn ; i++) + { + Diagonal_map [i] = EMPTY ; + Diagonal_imap [i] = EMPTY ; + } + for (k = n1 ; k < nn - nempty ; k++) + { + newrow = Symbolic->Diagonal_map [k] ; + Diagonal_map [k] = newrow ; + Diagonal_imap [newrow] = k ; + } + } + + /* ---------------------------------------------------------------------- */ + /* allocate O (n_row) workspace at the tail end of Memory */ + /* ---------------------------------------------------------------------- */ + + rpi = UMF_mem_alloc_tail_block (Numeric, UNITS (Int *, n_row+1)) ; + rpx = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry *, n_row+1)) ; + if (!rpi || !rpx) + { + /* :: pattern change (out of memory for Rpx, Rpx) :: */ + /* out of memory, which can only mean that the pattern has changed */ + return (FALSE) ; /* pattern changed */ + } + Rpi = (Int **) (Memory + rpx) ; + Rpx = (Entry **) (Memory + rpi) ; + + /* ---------------------------------------------------------------------- */ + /* allocate the LU factors for the columns of the singletons */ + /* ---------------------------------------------------------------------- */ + + DEBUG1 (("Allocating singletons:\n")) ; + for (k = 0 ; k < n1 ; k++) + { + lnz = Cdeg [k] - 1 ; + unz = Rdeg [k] - 1 ; + + DEBUG1 (("Singleton k "ID" pivrow "ID" pivcol "ID" cdeg "ID" rdeg " + ID"\n", k, Rperm_init [k], Cperm_init [k], Cdeg [k], Rdeg [k])) ; + ASSERT (unz >= 0 && lnz >= 0 && (lnz == 0 || unz == 0)) ; + DEBUG1 ((" lnz "ID" unz "ID"\n", lnz, unz)) ; + + size = UNITS (Int, lnz) + UNITS (Entry, lnz) + + UNITS (Int, unz) + UNITS (Entry, unz) ; + p = UMF_mem_alloc_head_block (Numeric, size) ; + DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ; + if (!p) + { + /* :: pattern change (out of memory for singletons) :: */ + DEBUG0 (("Pattern has gotten larger - kernel init failed\n")) ; + return (FALSE) ; /* pattern changed */ + } + + Numeric->all_lnz += lnz ; + Numeric->all_unz += unz ; + + /* allocate the column of L */ + lip = p ; + p += UNITS (Int, lnz) ; + p += UNITS (Entry, lnz) ; + + /* allocate the row of U */ + uip = p ; + Rpi [k] = (Int *) (Memory + p) ; + p += UNITS (Int, unz) ; + Rpx [k] = (Entry *) (Memory + p) ; + /* p += UNITS (Entry, unz) ; (not needed) */ + + /* a single column of L (no Lchains) */ + Lip [k] = lip ; + Lilen [k] = lnz ; + + /* a single row of L (no Uchains) */ + Uip [k] = uip ; + Uilen [k] = unz ; + + Wp [k] = unz ; + + /* save row and column inverse permutation */ + k1 = ONES_COMPLEMENT (k) ; + Rperm [k] = k1 ; /* aliased with Row_degree */ + Cperm [k] = k1 ; /* aliased with Col_degree */ + } + + /* ---------------------------------------------------------------------- */ + /* current frontal matrix is empty */ + /* ---------------------------------------------------------------------- */ + + e = 0 ; + E [e] = 0 ; + Work->Flublock = (Entry *) NULL ; + Work->Flblock = (Entry *) NULL ; + Work->Fublock = (Entry *) NULL ; + Work->Fcblock = (Entry *) NULL ; + + /* ---------------------------------------------------------------------- */ + /* allocate the column elements */ + /* ---------------------------------------------------------------------- */ + + Esize = Symbolic->Esize ; + empty_elements = FALSE ; + for (k = n1 ; k < n_col - nempty_col ; k++) + { + e = k - n1 + 1 ; + ASSERT (e < Work->elen) ; + esize = Esize ? Esize [k-n1] : Cdeg [k] ; + if (esize > 0) + { + /* allocate an element for this column */ + E [e] = UMF_mem_alloc_element (Numeric, esize, 1, &Rows, &Cols, &C, + &size, &ep) ; + if (E [e] <= 0) + { + /* :: pattern change (out of memory for column elements) :: */ + return (FALSE) ; /* pattern has changed */ + } + Cols [0] = k ; + DEBUG0 (("Got column element e "ID" esize "ID"\n", e, esize)) ; + } + else + { + /* all rows in this column are dense, or empty */ + E [e] = 0 ; + empty_elements = TRUE ; + DEBUG0 (("column element e is empty "ID"\n", e)) ; + } + } + DEBUG0 (("e "ID" n_col "ID" nempty_col "ID" n1 "ID"\n", e, n_col, + nempty_col, n1)) ; + ASSERT (e == n_col - nempty_col - n1) ; + + /* ---------------------------------------------------------------------- */ + /* allocate the row elements for dense rows of A (if any) */ + /* ---------------------------------------------------------------------- */ + + if (Esize) + { + for (k = n1 ; k < n_row - nempty_row ; k++) + { + rdeg = Rdeg [k] ; + if (rdeg > dense_row_threshold) + { + /* allocate an element for this dense row */ + e++ ; + ASSERT (e < Work->elen) ; + E [e] = UMF_mem_alloc_element (Numeric, 1, rdeg, &Rows, &Cols, + &C, &size, &ep) ; + if (E [e] <= 0) + { + /* :: pattern change (out of memory for row elements) :: */ + return (FALSE) ; /* pattern has changed */ + } + Rows [0] = k ; + Rpi [k] = Cols ; + Rpx [k] = C ; + Wp [k] = rdeg ; + DEBUG0 (("Got row element e "ID" rdeg "ID"\n", e, rdeg)) ; + } + } + } + + /* elements are currently in the range 0 to e */ + Work->nel = e ; + + /* ---------------------------------------------------------------------- */ + /* create the first n1 columns of L and U */ + /* ---------------------------------------------------------------------- */ + + for (k = 0 ; k < n1 ; k++) + { + pivcol = Cperm_init [k] ; + p2 = Ap [pivcol+1] ; + + /* get the kth column of L */ + p = Lip [k] ; + Li = (Int *) (Memory + p) ; + lilen = Lilen [k] ; + p += UNITS (Int, lilen) ; + Lval = (Entry *) (Memory + p) ; + + llen = 0 ; + + for (pa = Ap [pivcol] ; pa < p2 ; pa++) + { + oldrow = Ai [pa] ; + newrow = Frpos [oldrow] ; + ASSIGN (x, Ax, Az, pa, split) ; + + /* scale the value using the scale factors, Rs */ + if (do_scale) + { +#ifndef NRECIPROCAL + if (do_recip) + { + SCALE (x, Rs [oldrow]) ; + } + else +#endif + { + SCALE_DIV (x, Rs [oldrow]) ; + } + } + + if (newrow == k) + { + /* this is the pivot entry itself */ + ASSERT (oldrow == Rperm_init [k]) ; + D [k] = x ; + } + else if (newrow < k) + { + /* this entry goes in a row of U */ + DEBUG1 (("Singleton row of U: k "ID" newrow "ID"\n", + k, newrow)) ; + if (--(Wp [newrow]) < 0) + { + /* :: pattern change (singleton row too long) :: */ + DEBUGm4 (("bad U singleton row (too long)\n")) ; + return (FALSE) ; /* pattern changed */ + } + *(Rpi [newrow]++) = k ; + *(Rpx [newrow]++) = x ; + } + else + { + /* this entry goes in a column of L */ + DEBUG1 (("Singleton col of L: k "ID" newrow "ID"\n", + k, newrow)) ; + if (llen >= lilen) + { + DEBUGm4 (("bad L singleton col (too long)\n")) ; + return (FALSE) ; /* pattern changed */ + } + Li [llen] = newrow ; + Lval [llen] = x ; + llen++ ; + } + } + + if (llen != lilen) + { + /* :: pattern change (singleton column too long) :: */ + DEBUGm4 (("bad L singleton col (too short)\n")) ; + return (FALSE) ; /* pattern changed */ + } + + /* scale the column of L */ + if (llen > 0) + { + pivot_value = D [k] ; + UMF_scale (llen, pivot_value, Lval) ; + } + + } + + /* ---------------------------------------------------------------------- */ + /* allocate the elements and copy the columns of A */ + /* ---------------------------------------------------------------------- */ + + /* also apply the row and column pre-ordering. */ + for (k = n1 ; k < n_col ; k++) + { + /* The newcol is k, which is what the name of the column is in the + * UMFPACK kernel. The user's name for the column is oldcol. */ + oldcol = Cperm_init [k] ; + + ASSERT (oldcol >= 0 && oldcol < n_col) ; + + p2 = Ap [oldcol+1] ; + + cdeg = Cdeg [k] ; + ASSERT (cdeg >= 0) ; + ASSERT (IMPLIES ( + (Symbolic->ordering != UMFPACK_ORDERING_GIVEN) && n1 > 0, + cdeg > 1 || cdeg == 0)) ; + + /* if fixQ: set Col_degree to 0 for the NON_PIVOTAL_COL macro */ + Col_degree [k] = fixQ ? 0 : cdeg ; + + /* get the element for this column (if any) */ + e = k - n1 + 1 ; + if (k < n_col - nempty_col) + { + esize = Esize ? Esize [k-n1] : cdeg ; + if (E [e]) + { + Int ncols, nrows ; + Unit *pp ; + pp = Memory + E [e] ; + GET_ELEMENT (ep, pp, Cols, Rows, ncols, nrows, C) ; + ASSERT (ncols == 1) ; + ASSERT (nrows == esize) ; + ASSERT (Cols [0] == k) ; + } + } + else + { + ASSERT (cdeg == 0) ; + esize = 0 ; + } + + clen = 0 ; + + for (pa = Ap [oldcol] ; pa < p2 ; pa++) + { + oldrow = Ai [pa] ; + newrow = Frpos [oldrow] ; + ASSIGN (x, Ax, Az, pa, split) ; + + /* scale the value using the scale factors, Rs */ + if (do_scale) + { +#ifndef NRECIPROCAL + if (do_recip) + { + /* multiply by the reciprocal */ + SCALE (x, Rs [oldrow]) ; + } + else +#endif + { + /* divide instead */ + SCALE_DIV (x, Rs [oldrow]) ; + } + } + + rdeg = Rdeg [newrow] ; + if (newrow < n1 || rdeg > dense_row_threshold) + { + /* this entry goes in a row of U or into a dense row */ + DEBUG1 (("Singleton/dense row of U: k "ID" newrow "ID"\n", + k, newrow)) ; + if (--(Wp [newrow]) < 0) + { + DEBUGm4 (("bad row of U or A (too long)\n")) ; + return (FALSE) ; /* pattern changed */ + } + *(Rpi [newrow]++) = k ; + *(Rpx [newrow]++) = x ; + } + else + { + /* this entry goes in an initial element */ + DEBUG1 (("In element k "ID" e "ID" newrow "ID"\n", + k, e, newrow)) ; + if (clen >= esize) + { + DEBUGm4 (("bad A column (too long)\n")) ; + return (FALSE) ; /* pattern changed */ + } + ASSERT (E [e]) ; + ASSERT (k < n_col - nempty_col) ; + Rows [clen] = newrow ; + C [clen] = x ; + clen++ ; +#ifndef NDEBUG + if (Diagonal_map && (newrow == Diagonal_map [k])) + { + DEBUG0 (("Diagonal: old: row "ID" col "ID" : " + "new: row "ID" col "ID" : ", + oldrow, oldcol, newrow, k)) ; + EDEBUGk (0, x) ; + } +#endif + } + } + + if (clen != esize) + { + /* :: pattern change (singleton column too short) :: */ + DEBUGm4 (("bad A column (too short)\n")) ; + return (FALSE) ; /* pattern changed */ + } + } + + /* ---------------------------------------------------------------------- */ + /* free the Rpi and Rpx workspace at the tail end of memory */ + /* ---------------------------------------------------------------------- */ + + UMF_mem_free_tail_block (Numeric, rpi) ; + UMF_mem_free_tail_block (Numeric, rpx) ; + + /* ---------------------------------------------------------------------- */ + /* prune zeros and small entries from the singleton rows and columns */ + /* ---------------------------------------------------------------------- */ + + if (n1 > 0) + { + pnew = Lip [0] ; + ASSERT (pnew == 1) ; + for (k = 0 ; k < n1 ; k++) + { + DEBUGm4 (("\nPrune singleton L col "ID"\n", k)) ; + pnew = packsp (pnew, &Lip [k], &Lilen [k], drop, droptol, Memory) ; + Numeric->lnz += Lilen [k] ; + DEBUGm4 (("\nPrune singleton U row "ID"\n", k)) ; + pnew = packsp (pnew, &Uip [k], &Uilen [k], drop, droptol, Memory) ; + Numeric->unz += Uilen [k] ; + } + /* free the unused space at the head of memory */ + Numeric->ihead = pnew ; + } + + /* ---------------------------------------------------------------------- */ + /* initialize row degrees */ + /* ---------------------------------------------------------------------- */ + + for (k = 0 ; k < n1 ; k++) + { + if (Wp [k] != 0) + { + /* :: pattern change (singleton row too short) :: */ + DEBUGm4 (("bad U singleton row (too short)\n")) ; + return (FALSE) ; /* pattern changed */ + } + } + + for (k = n1 ; k < n_row ; k++) + { + DEBUG1 (("Initial row degree k "ID" oldrow "ID" Rdeg "ID"\n", + k, Rperm_init [k], Rdeg [k])) ; + rdeg = Rdeg [k] ; + Row_degree [k] = rdeg ; + if (rdeg > dense_row_threshold && Wp [k] != 0) + { + /* :: pattern change (dense row too short) :: */ + DEBUGm4 (("bad dense row (too short)\n")) ; + return (FALSE) ; /* pattern changed */ + } + } + +#ifndef NDEBUG + if (prefer_diagonal) + { + Entry aij ; + Int *InvCperm, newcol ; + UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, n1, nn, nempty) ; + InvCperm = (Int *) malloc (n_col * sizeof (Int)) ; + ASSERT (InvCperm != (Int *) NULL) ; + for (newcol = 0 ; newcol < n_col ; newcol++) + { + oldcol = Cperm_init [newcol] ; + InvCperm [oldcol] = newcol ; + } + DEBUGm3 (("Diagonal of P2*A:\n")) ; + for (oldcol = 0 ; oldcol < n_col ; oldcol++) + { + newcol = InvCperm [oldcol] ; + for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++) + { + oldrow = Ai [p] ; + newrow = Frpos [oldrow] ; + ASSIGN (aij, Ax, Az, p, split) ; + if (newrow == Diagonal_map [newcol]) + { + DEBUG0 (("old row "ID" col "ID" new row "ID" col "ID, + oldrow, oldcol, newrow, newcol)) ; + EDEBUGk (0, aij) ; + DEBUG0 ((" scaled ")) ; + if (do_scale) + { +#ifndef NRECIPROCAL + if (do_recip) + { + SCALE (aij, Rs [oldrow]) ; + } + else +#endif + { + SCALE_DIV (aij, Rs [oldrow]) ; + } + } + EDEBUGk (0, aij) ; + DEBUG0 (("\n")) ; + } + } + } + free (InvCperm) ; + } +#endif + + Col_degree [n_col] = 0 ; + + /* ---------------------------------------------------------------------- */ + /* pack the element name space */ + /* ---------------------------------------------------------------------- */ + + if (empty_elements) + { + Int e2 = 0 ; + DEBUG0 (("\n\n============= Packing element space\n")) ; + for (e = 1 ; e <= Work->nel ; e++) + { + if (E [e]) + { + e2++ ; + E [e2] = E [e] ; + } + } + Work->nel = e2 ; + } + +#ifndef NDEBUG + DEBUG0 (("Number of initial elements: "ID"\n", Work->nel)) ; + for (e = 0 ; e <= Work->nel ; e++) UMF_dump_element (Numeric, Work,e,TRUE) ; +#endif + + for (e = Work->nel + 1 ; e < Work->elen ; e++) + { + E [e] = 0 ; + } + + /* Frpos no longer needed */ + for (row = 0 ; row <= n_row ; row++) + { + Frpos [row] = EMPTY ; + } + + /* clear Wp */ + for (i = 0 ; i <= nn ; i++) + { + Wp [i] = EMPTY ; + } + + DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ; + + /* ---------------------------------------------------------------------- */ + /* build the tuple lists */ + /* ---------------------------------------------------------------------- */ + + /* if the memory usage changes, then the pattern has changed */ + + (void) UMF_tuple_lengths (Numeric, Work, &unused) ; + if (!UMF_build_tuples (Numeric, Work)) + { + /* :: pattern change (out of memory in umf_build_tuples) :: */ + /* We ran out of memory, which can only mean that */ + /* the pattern (Ap and or Ai) has changed (gotten larger). */ + DEBUG0 (("Pattern has gotten larger - build tuples failed\n")) ; + return (FALSE) ; /* pattern changed */ + } + + Numeric->init_usage = Numeric->max_usage ; + + /* ---------------------------------------------------------------------- */ + /* construct the row merge sets */ + /* ---------------------------------------------------------------------- */ + + for (i = 0 ; i <= Symbolic->nfr ; i++) + { + Work->Front_new1strow [i] = Symbolic->Front_1strow [i] ; + } + +#ifndef NDEBUG + UMF_dump_rowmerge (Numeric, Symbolic, Work) ; + DEBUG6 (("Column form of original matrix:\n")) ; + UMF_dump_col_matrix (Ax, +#ifdef COMPLEX + Az, +#endif + Ai, Ap, n_row, n_col, nz) ; + UMF_dump_memory (Numeric) ; + UMF_dump_matrix (Numeric, Work, FALSE) ; + DEBUG0 (("kernel init done...\n")) ; +#endif + + return (TRUE) ; +}