Mercurial > octave-nkf
diff liboctave/UMFPACK/UMFPACK/Source/umf_kernel_wrapup.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_wrapup.c Fri Feb 25 19:55:28 2005 +0000 @@ -0,0 +1,466 @@ +/* ========================================================================== */ +/* === UMF_kernel_wrapup ==================================================== */ +/* ========================================================================== */ + +/* -------------------------------------------------------------------------- */ +/* 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 */ +/* -------------------------------------------------------------------------- */ + +/* The matrix is factorized. Finish the LU data structure. */ + +#include "umf_internal.h" + +GLOBAL void UMF_kernel_wrapup +( + NumericType *Numeric, + SymbolicType *Symbolic, + WorkType *Work +) +{ + + /* ---------------------------------------------------------------------- */ + /* local variables */ + /* ---------------------------------------------------------------------- */ + + Entry pivot_value ; + double d ; + Entry *D ; + Int i, k, col, row, llen, ulen, *ip, *Rperm, *Cperm, *Lilen, npiv, lp, + *Uilen, *Lip, *Uip, *Cperm_init, up, pivrow, pivcol, *Lpos, *Upos, *Wr, + *Wc, *Wp, *Frpos, *Fcpos, *Row_degree, *Col_degree, *Rperm_init, + n_row, n_col, n_inner, zero_pivot, nan_pivot, n1 ; + +#ifndef NDEBUG + UMF_dump_matrix (Numeric, Work, FALSE) ; +#endif + + DEBUG0 (("Kernel complete, Starting Kernel wrapup\n")) ; + n_row = Symbolic->n_row ; + n_col = Symbolic->n_col ; + n_inner = MIN (n_row, n_col) ; + Rperm = Numeric->Rperm ; + Cperm = Numeric->Cperm ; + Lilen = Numeric->Lilen ; + Uilen = Numeric->Uilen ; + Upos = Numeric->Upos ; + Lpos = Numeric->Lpos ; + Lip = Numeric->Lip ; + Uip = Numeric->Uip ; + D = Numeric->D ; + + npiv = Work->npiv ; + Numeric->npiv = npiv ; + Numeric->ulen = Work->ulen ; + + ASSERT (n_row == Numeric->n_row) ; + ASSERT (n_col == Symbolic->n_col) ; + DEBUG0 (("Wrap-up: npiv "ID" ulen "ID"\n", npiv, Numeric->ulen)) ; + ASSERT (npiv <= n_inner) ; + + /* this will be nonzero only if matrix is singular or rectangular */ + ASSERT (IMPLIES (npiv == n_col, Work->ulen == 0)) ; + + /* ---------------------------------------------------------------------- */ + /* find the smallest and largest entries in D */ + /* ---------------------------------------------------------------------- */ + + for (k = 0 ; k < npiv ; k++) + { + pivot_value = D [k] ; + ABS (d, pivot_value) ; + zero_pivot = SCALAR_IS_ZERO (d) ; + nan_pivot = SCALAR_IS_NAN (d) ; + + if (!zero_pivot) + { + /* the pivot is nonzero, but might be Inf or NaN */ + Numeric->nnzpiv++ ; + } + + if (k == 0) + { + Numeric->min_udiag = d ; + Numeric->max_udiag = d ; + } + else + { + /* min (abs (diag (U))) behaves as follows: If any entry is zero, + then the result is zero (regardless of the presence of NaN's). + Otherwise, if any entry is NaN, then the result is NaN. + Otherwise, the result is the smallest absolute value on the + diagonal of U. + */ + + if (SCALAR_IS_NONZERO (Numeric->min_udiag)) + { + if (zero_pivot || nan_pivot) + { + Numeric->min_udiag = d ; + } + else if (!SCALAR_IS_NAN (Numeric->min_udiag)) + { + /* d and min_udiag are both non-NaN */ + Numeric->min_udiag = MIN (Numeric->min_udiag, d) ; + } + } + + /* + max (abs (diag (U))) behaves as follows: If any entry is NaN + then the result is NaN. Otherise, the result is the largest + absolute value on the diagonal of U. + */ + + if (nan_pivot) + { + Numeric->max_udiag = d ; + } + else if (!SCALAR_IS_NAN (Numeric->max_udiag)) + { + /* d and max_udiag are both non-NaN */ + Numeric->max_udiag = MAX (Numeric->max_udiag, d) ; + } + } + } + + /* ---------------------------------------------------------------------- */ + /* check if matrix is singular or rectangular */ + /* ---------------------------------------------------------------------- */ + + Col_degree = Cperm ; /* for NON_PIVOTAL_COL macro */ + Row_degree = Rperm ; /* for NON_PIVOTAL_ROW macro */ + + if (npiv < n_row) + { + /* finalize the row permutation */ + k = npiv ; + DEBUGm3 (("Singular pivot rows "ID" to "ID"\n", k, n_row-1)) ; + for (row = 0 ; row < n_row ; row++) + { + if (NON_PIVOTAL_ROW (row)) + { + Rperm [row] = ONES_COMPLEMENT (k) ; + DEBUGm3 (("Singular row "ID" is k: "ID" pivot row\n", row, k)) ; + ASSERT (!NON_PIVOTAL_ROW (row)) ; + Lpos [row] = EMPTY ; + Uip [row] = EMPTY ; + Uilen [row] = 0 ; + k++ ; + } + } + ASSERT (k == n_row) ; + } + + if (npiv < n_col) + { + /* finalize the col permutation */ + k = npiv ; + DEBUGm3 (("Singular pivot cols "ID" to "ID"\n", k, n_col-1)) ; + for (col = 0 ; col < n_col ; col++) + { + if (NON_PIVOTAL_COL (col)) + { + Cperm [col] = ONES_COMPLEMENT (k) ; + DEBUGm3 (("Singular col "ID" is k: "ID" pivot row\n", col, k)) ; + ASSERT (!NON_PIVOTAL_COL (col)) ; + Upos [col] = EMPTY ; + Lip [col] = EMPTY ; + Lilen [col] = 0 ; + k++ ; + } + } + ASSERT (k == n_col) ; + } + + if (npiv < n_inner) + { + /* finalize the diagonal of U */ + DEBUGm3 (("Diag of U is zero, "ID" to "ID"\n", npiv, n_inner-1)) ; + for (k = npiv ; k < n_inner ; k++) + { + CLEAR (D [k]) ; + } + } + + /* save the pattern of the last row of U */ + if (Numeric->ulen > 0) + { + DEBUGm3 (("Last row of U is not empty\n")) ; + Numeric->Upattern = Work->Upattern ; + Work->Upattern = (Int *) NULL ; + } + + DEBUG2 (("Nnzpiv: "ID" npiv "ID"\n", Numeric->nnzpiv, npiv)) ; + ASSERT (Numeric->nnzpiv <= npiv) ; + if (Numeric->nnzpiv < n_inner && !SCALAR_IS_NAN (Numeric->min_udiag)) + { + /* the rest of the diagonal is zero, so min_udiag becomes 0, + * unless it is already NaN. */ + Numeric->min_udiag = 0.0 ; + } + + /* ---------------------------------------------------------------------- */ + /* size n_row, n_col workspaces that can be used here: */ + /* ---------------------------------------------------------------------- */ + + Frpos = Work->Frpos ; /* of size n_row+1 */ + Fcpos = Work->Fcpos ; /* of size n_col+1 */ + Wp = Work->Wp ; /* of size MAX(n_row,n_col)+1 */ + /* Work->Upattern ; cannot be used (in Numeric) */ + Wr = Work->Lpattern ; /* of size n_row+1 */ + Wc = Work->Wrp ; /* of size n_col+1 or bigger */ + + /* ---------------------------------------------------------------------- */ + /* construct Rperm from inverse permutations */ + /* ---------------------------------------------------------------------- */ + + /* use Frpos for temporary copy of inverse row permutation [ */ + + for (pivrow = 0 ; pivrow < n_row ; pivrow++) + { + k = Rperm [pivrow] ; + ASSERT (k < 0) ; + k = ONES_COMPLEMENT (k) ; + ASSERT (k >= 0 && k < n_row) ; + Wp [k] = pivrow ; + Frpos [pivrow] = k ; + } + for (k = 0 ; k < n_row ; k++) + { + Rperm [k] = Wp [k] ; + } + + /* ---------------------------------------------------------------------- */ + /* construct Cperm from inverse permutation */ + /* ---------------------------------------------------------------------- */ + + /* use Fcpos for temporary copy of inverse column permutation [ */ + + for (pivcol = 0 ; pivcol < n_col ; pivcol++) + { + k = Cperm [pivcol] ; + ASSERT (k < 0) ; + k = ONES_COMPLEMENT (k) ; + ASSERT (k >= 0 && k < n_col) ; + Wp [k] = pivcol ; + /* save a copy of the inverse column permutation in Fcpos */ + Fcpos [pivcol] = k ; + } + for (k = 0 ; k < n_col ; k++) + { + Cperm [k] = Wp [k] ; + } + +#ifndef NDEBUG + for (k = 0 ; k < n_col ; k++) + { + col = Cperm [k] ; + ASSERT (col >= 0 && col < n_col) ; + ASSERT (Fcpos [col] == k) ; /* col is the kth pivot */ + } + for (k = 0 ; k < n_row ; k++) + { + row = Rperm [k] ; + ASSERT (row >= 0 && row < n_row) ; + ASSERT (Frpos [row] == k) ; /* row is the kth pivot */ + } +#endif + +#ifndef NDEBUG + UMF_dump_lu (Numeric) ; +#endif + + /* ---------------------------------------------------------------------- */ + /* permute Lpos, Upos, Lilen, Lip, Uilen, and Uip */ + /* ---------------------------------------------------------------------- */ + + for (k = 0 ; k < npiv ; k++) + { + pivrow = Rperm [k] ; + Wr [k] = Uilen [pivrow] ; + Wp [k] = Uip [pivrow] ; + } + + for (k = 0 ; k < npiv ; k++) + { + Uilen [k] = Wr [k] ; + Uip [k] = Wp [k] ; + } + + for (k = 0 ; k < npiv ; k++) + { + pivrow = Rperm [k] ; + Wp [k] = Lpos [pivrow] ; + } + + for (k = 0 ; k < npiv ; k++) + { + Lpos [k] = Wp [k] ; + } + + for (k = 0 ; k < npiv ; k++) + { + pivcol = Cperm [k] ; + Wc [k] = Lilen [pivcol] ; + Wp [k] = Lip [pivcol] ; + } + + for (k = 0 ; k < npiv ; k++) + { + Lilen [k] = Wc [k] ; + Lip [k] = Wp [k] ; + } + + for (k = 0 ; k < npiv ; k++) + { + pivcol = Cperm [k] ; + Wp [k] = Upos [pivcol] ; + } + + for (k = 0 ; k < npiv ; k++) + { + Upos [k] = Wp [k] ; + } + + /* ---------------------------------------------------------------------- */ + /* terminate the last Uchain and last Lchain */ + /* ---------------------------------------------------------------------- */ + + Upos [npiv] = EMPTY ; + Lpos [npiv] = EMPTY ; + Uip [npiv] = EMPTY ; + Lip [npiv] = EMPTY ; + Uilen [npiv] = 0 ; + Lilen [npiv] = 0 ; + + /* ---------------------------------------------------------------------- */ + /* convert U to the new pivot order */ + /* ---------------------------------------------------------------------- */ + + n1 = Symbolic->n1 ; + + for (k = 0 ; k < n1 ; k++) + { + /* this is a singleton row of U */ + ulen = Uilen [k] ; + DEBUG4 (("K "ID" New U. ulen "ID" Singleton 1\n", k, ulen)) ; + if (ulen > 0) + { + up = Uip [k] ; + ip = (Int *) (Numeric->Memory + up) ; + for (i = 0 ; i < ulen ; i++) + { + col = *ip ; + DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])); + ASSERT (col >= 0 && col < n_col) ; + *ip++ = Fcpos [col] ; + } + } + } + + for (k = n1 ; k < npiv ; k++) + { + up = Uip [k] ; + if (up < 0) + { + /* this is the start of a new Uchain (with a pattern) */ + ulen = Uilen [k] ; + DEBUG4 (("K "ID" New U. ulen "ID" End_Uchain 1\n", k, ulen)) ; + if (ulen > 0) + { + up = -up ; + ip = (Int *) (Numeric->Memory + up) ; + for (i = 0 ; i < ulen ; i++) + { + col = *ip ; + DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])); + ASSERT (col >= 0 && col < n_col) ; + *ip++ = Fcpos [col] ; + } + } + } + } + + ulen = Numeric->ulen ; + if (ulen > 0) + { + /* convert last pivot row of U to the new pivot order */ + DEBUG4 (("K "ID" (last)\n", k)) ; + for (i = 0 ; i < ulen ; i++) + { + col = Numeric->Upattern [i] ; + DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])) ; + Numeric->Upattern [i] = Fcpos [col] ; + } + } + + /* Fcpos no longer needed ] */ + + /* ---------------------------------------------------------------------- */ + /* convert L to the new pivot order */ + /* ---------------------------------------------------------------------- */ + + for (k = 0 ; k < n1 ; k++) + { + llen = Lilen [k] ; + DEBUG4 (("K "ID" New L. llen "ID" Singleton col\n", k, llen)) ; + if (llen > 0) + { + lp = Lip [k] ; + ip = (Int *) (Numeric->Memory + lp) ; + for (i = 0 ; i < llen ; i++) + { + row = *ip ; + DEBUG4 ((" old row "ID" new row "ID"\n", row, Frpos [row])) ; + ASSERT (row >= 0 && row < n_row) ; + *ip++ = Frpos [row] ; + } + } + } + + for (k = n1 ; k < npiv ; k++) + { + llen = Lilen [k] ; + DEBUG4 (("K "ID" New L. llen "ID" \n", k, llen)) ; + if (llen > 0) + { + lp = Lip [k] ; + if (lp < 0) + { + /* this starts a new Lchain */ + lp = -lp ; + } + ip = (Int *) (Numeric->Memory + lp) ; + for (i = 0 ; i < llen ; i++) + { + row = *ip ; + DEBUG4 ((" old row "ID" new row "ID"\n", row, Frpos [row])) ; + ASSERT (row >= 0 && row < n_row) ; + *ip++ = Frpos [row] ; + } + } + } + + /* Frpos no longer needed ] */ + + /* ---------------------------------------------------------------------- */ + /* combine symbolic and numeric permutations */ + /* ---------------------------------------------------------------------- */ + + Cperm_init = Symbolic->Cperm_init ; + Rperm_init = Symbolic->Rperm_init ; + + for (k = 0 ; k < n_row ; k++) + { + Rperm [k] = Rperm_init [Rperm [k]] ; + } + + for (k = 0 ; k < n_col ; k++) + { + Cperm [k] = Cperm_init [Cperm [k]] ; + } + + /* Work object will be freed immediately upon return (to UMF_kernel */ + /* and then to UMFPACK_numeric). */ +}