Path: blob/devel/umfpack/src/umfpack/umf_kernel_wrapup.c
3203 views
/* ========================================================================== */1/* === UMF_kernel_wrapup ==================================================== */2/* ========================================================================== */34/* -------------------------------------------------------------------------- */5/* UMFPACK Version 4.4, Copyright (c) 2005 by Timothy A. Davis. CISE Dept, */6/* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */7/* web: http://www.cise.ufl.edu/research/sparse/umfpack */8/* -------------------------------------------------------------------------- */910/* The matrix is factorized. Finish the LU data structure. */1112#include "umf_internal.h"1314GLOBAL void UMF_kernel_wrapup15(16NumericType *Numeric,17SymbolicType *Symbolic,18WorkType *Work19)20{2122/* ---------------------------------------------------------------------- */23/* local variables */24/* ---------------------------------------------------------------------- */2526Entry pivot_value ;27double d ;28Entry *D ;29Int i, k, col, row, llen, ulen, *ip, *Rperm, *Cperm, *Lilen, npiv, lp,30*Uilen, *Lip, *Uip, *Cperm_init, up, pivrow, pivcol, *Lpos, *Upos, *Wr,31*Wc, *Wp, *Frpos, *Fcpos, *Row_degree, *Col_degree, *Rperm_init,32n_row, n_col, n_inner, zero_pivot, nan_pivot, n1 ;3334#ifndef NDEBUG35UMF_dump_matrix (Numeric, Work, FALSE) ;36#endif3738DEBUG0 (("Kernel complete, Starting Kernel wrapup\n")) ;39n_row = Symbolic->n_row ;40n_col = Symbolic->n_col ;41n_inner = MIN (n_row, n_col) ;42Rperm = Numeric->Rperm ;43Cperm = Numeric->Cperm ;44Lilen = Numeric->Lilen ;45Uilen = Numeric->Uilen ;46Upos = Numeric->Upos ;47Lpos = Numeric->Lpos ;48Lip = Numeric->Lip ;49Uip = Numeric->Uip ;50D = Numeric->D ;5152npiv = Work->npiv ;53Numeric->npiv = npiv ;54Numeric->ulen = Work->ulen ;5556ASSERT (n_row == Numeric->n_row) ;57ASSERT (n_col == Symbolic->n_col) ;58DEBUG0 (("Wrap-up: npiv "ID" ulen "ID"\n", npiv, Numeric->ulen)) ;59ASSERT (npiv <= n_inner) ;6061/* this will be nonzero only if matrix is singular or rectangular */62ASSERT (IMPLIES (npiv == n_col, Work->ulen == 0)) ;6364/* ---------------------------------------------------------------------- */65/* find the smallest and largest entries in D */66/* ---------------------------------------------------------------------- */6768for (k = 0 ; k < npiv ; k++)69{70pivot_value = D [k] ;71ABS (d, pivot_value) ;72zero_pivot = SCALAR_IS_ZERO (d) ;73nan_pivot = SCALAR_IS_NAN (d) ;7475if (!zero_pivot)76{77/* the pivot is nonzero, but might be Inf or NaN */78Numeric->nnzpiv++ ;79}8081if (k == 0)82{83Numeric->min_udiag = d ;84Numeric->max_udiag = d ;85}86else87{88/* min (abs (diag (U))) behaves as follows: If any entry is zero,89then the result is zero (regardless of the presence of NaN's).90Otherwise, if any entry is NaN, then the result is NaN.91Otherwise, the result is the smallest absolute value on the92diagonal of U.93*/9495if (SCALAR_IS_NONZERO (Numeric->min_udiag))96{97if (zero_pivot || nan_pivot)98{99Numeric->min_udiag = d ;100}101else if (!SCALAR_IS_NAN (Numeric->min_udiag))102{103/* d and min_udiag are both non-NaN */104Numeric->min_udiag = MIN (Numeric->min_udiag, d) ;105}106}107108/*109max (abs (diag (U))) behaves as follows: If any entry is NaN110then the result is NaN. Otherise, the result is the largest111absolute value on the diagonal of U.112*/113114if (nan_pivot)115{116Numeric->max_udiag = d ;117}118else if (!SCALAR_IS_NAN (Numeric->max_udiag))119{120/* d and max_udiag are both non-NaN */121Numeric->max_udiag = MAX (Numeric->max_udiag, d) ;122}123}124}125126/* ---------------------------------------------------------------------- */127/* check if matrix is singular or rectangular */128/* ---------------------------------------------------------------------- */129130Col_degree = Cperm ; /* for NON_PIVOTAL_COL macro */131Row_degree = Rperm ; /* for NON_PIVOTAL_ROW macro */132133if (npiv < n_row)134{135/* finalize the row permutation */136k = npiv ;137DEBUGm3 (("Singular pivot rows "ID" to "ID"\n", k, n_row-1)) ;138for (row = 0 ; row < n_row ; row++)139{140if (NON_PIVOTAL_ROW (row))141{142Rperm [row] = ONES_COMPLEMENT (k) ;143DEBUGm3 (("Singular row "ID" is k: "ID" pivot row\n", row, k)) ;144ASSERT (!NON_PIVOTAL_ROW (row)) ;145Lpos [row] = EMPTY ;146Uip [row] = EMPTY ;147Uilen [row] = 0 ;148k++ ;149}150}151ASSERT (k == n_row) ;152}153154if (npiv < n_col)155{156/* finalize the col permutation */157k = npiv ;158DEBUGm3 (("Singular pivot cols "ID" to "ID"\n", k, n_col-1)) ;159for (col = 0 ; col < n_col ; col++)160{161if (NON_PIVOTAL_COL (col))162{163Cperm [col] = ONES_COMPLEMENT (k) ;164DEBUGm3 (("Singular col "ID" is k: "ID" pivot row\n", col, k)) ;165ASSERT (!NON_PIVOTAL_COL (col)) ;166Upos [col] = EMPTY ;167Lip [col] = EMPTY ;168Lilen [col] = 0 ;169k++ ;170}171}172ASSERT (k == n_col) ;173}174175if (npiv < n_inner)176{177/* finalize the diagonal of U */178DEBUGm3 (("Diag of U is zero, "ID" to "ID"\n", npiv, n_inner-1)) ;179for (k = npiv ; k < n_inner ; k++)180{181CLEAR (D [k]) ;182}183}184185/* save the pattern of the last row of U */186if (Numeric->ulen > 0)187{188DEBUGm3 (("Last row of U is not empty\n")) ;189Numeric->Upattern = Work->Upattern ;190Work->Upattern = (Int *) NULL ;191}192193DEBUG2 (("Nnzpiv: "ID" npiv "ID"\n", Numeric->nnzpiv, npiv)) ;194ASSERT (Numeric->nnzpiv <= npiv) ;195if (Numeric->nnzpiv < n_inner && !SCALAR_IS_NAN (Numeric->min_udiag))196{197/* the rest of the diagonal is zero, so min_udiag becomes 0,198* unless it is already NaN. */199Numeric->min_udiag = 0.0 ;200}201202/* ---------------------------------------------------------------------- */203/* size n_row, n_col workspaces that can be used here: */204/* ---------------------------------------------------------------------- */205206Frpos = Work->Frpos ; /* of size n_row+1 */207Fcpos = Work->Fcpos ; /* of size n_col+1 */208Wp = Work->Wp ; /* of size MAX(n_row,n_col)+1 */209/* Work->Upattern ; cannot be used (in Numeric) */210Wr = Work->Lpattern ; /* of size n_row+1 */211Wc = Work->Wrp ; /* of size n_col+1 or bigger */212213/* ---------------------------------------------------------------------- */214/* construct Rperm from inverse permutations */215/* ---------------------------------------------------------------------- */216217/* use Frpos for temporary copy of inverse row permutation [ */218219for (pivrow = 0 ; pivrow < n_row ; pivrow++)220{221k = Rperm [pivrow] ;222ASSERT (k < 0) ;223k = ONES_COMPLEMENT (k) ;224ASSERT (k >= 0 && k < n_row) ;225Wp [k] = pivrow ;226Frpos [pivrow] = k ;227}228for (k = 0 ; k < n_row ; k++)229{230Rperm [k] = Wp [k] ;231}232233/* ---------------------------------------------------------------------- */234/* construct Cperm from inverse permutation */235/* ---------------------------------------------------------------------- */236237/* use Fcpos for temporary copy of inverse column permutation [ */238239for (pivcol = 0 ; pivcol < n_col ; pivcol++)240{241k = Cperm [pivcol] ;242ASSERT (k < 0) ;243k = ONES_COMPLEMENT (k) ;244ASSERT (k >= 0 && k < n_col) ;245Wp [k] = pivcol ;246/* save a copy of the inverse column permutation in Fcpos */247Fcpos [pivcol] = k ;248}249for (k = 0 ; k < n_col ; k++)250{251Cperm [k] = Wp [k] ;252}253254#ifndef NDEBUG255for (k = 0 ; k < n_col ; k++)256{257col = Cperm [k] ;258ASSERT (col >= 0 && col < n_col) ;259ASSERT (Fcpos [col] == k) ; /* col is the kth pivot */260}261for (k = 0 ; k < n_row ; k++)262{263row = Rperm [k] ;264ASSERT (row >= 0 && row < n_row) ;265ASSERT (Frpos [row] == k) ; /* row is the kth pivot */266}267#endif268269#ifndef NDEBUG270UMF_dump_lu (Numeric) ;271#endif272273/* ---------------------------------------------------------------------- */274/* permute Lpos, Upos, Lilen, Lip, Uilen, and Uip */275/* ---------------------------------------------------------------------- */276277for (k = 0 ; k < npiv ; k++)278{279pivrow = Rperm [k] ;280Wr [k] = Uilen [pivrow] ;281Wp [k] = Uip [pivrow] ;282}283284for (k = 0 ; k < npiv ; k++)285{286Uilen [k] = Wr [k] ;287Uip [k] = Wp [k] ;288}289290for (k = 0 ; k < npiv ; k++)291{292pivrow = Rperm [k] ;293Wp [k] = Lpos [pivrow] ;294}295296for (k = 0 ; k < npiv ; k++)297{298Lpos [k] = Wp [k] ;299}300301for (k = 0 ; k < npiv ; k++)302{303pivcol = Cperm [k] ;304Wc [k] = Lilen [pivcol] ;305Wp [k] = Lip [pivcol] ;306}307308for (k = 0 ; k < npiv ; k++)309{310Lilen [k] = Wc [k] ;311Lip [k] = Wp [k] ;312}313314for (k = 0 ; k < npiv ; k++)315{316pivcol = Cperm [k] ;317Wp [k] = Upos [pivcol] ;318}319320for (k = 0 ; k < npiv ; k++)321{322Upos [k] = Wp [k] ;323}324325/* ---------------------------------------------------------------------- */326/* terminate the last Uchain and last Lchain */327/* ---------------------------------------------------------------------- */328329Upos [npiv] = EMPTY ;330Lpos [npiv] = EMPTY ;331Uip [npiv] = EMPTY ;332Lip [npiv] = EMPTY ;333Uilen [npiv] = 0 ;334Lilen [npiv] = 0 ;335336/* ---------------------------------------------------------------------- */337/* convert U to the new pivot order */338/* ---------------------------------------------------------------------- */339340n1 = Symbolic->n1 ;341342for (k = 0 ; k < n1 ; k++)343{344/* this is a singleton row of U */345ulen = Uilen [k] ;346DEBUG4 (("K "ID" New U. ulen "ID" Singleton 1\n", k, ulen)) ;347if (ulen > 0)348{349up = Uip [k] ;350ip = (Int *) (Numeric->Memory + up) ;351for (i = 0 ; i < ulen ; i++)352{353col = *ip ;354DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));355ASSERT (col >= 0 && col < n_col) ;356*ip++ = Fcpos [col] ;357}358}359}360361for (k = n1 ; k < npiv ; k++)362{363up = Uip [k] ;364if (up < 0)365{366/* this is the start of a new Uchain (with a pattern) */367ulen = Uilen [k] ;368DEBUG4 (("K "ID" New U. ulen "ID" End_Uchain 1\n", k, ulen)) ;369if (ulen > 0)370{371up = -up ;372ip = (Int *) (Numeric->Memory + up) ;373for (i = 0 ; i < ulen ; i++)374{375col = *ip ;376DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));377ASSERT (col >= 0 && col < n_col) ;378*ip++ = Fcpos [col] ;379}380}381}382}383384ulen = Numeric->ulen ;385if (ulen > 0)386{387/* convert last pivot row of U to the new pivot order */388DEBUG4 (("K "ID" (last)\n", k)) ;389for (i = 0 ; i < ulen ; i++)390{391col = Numeric->Upattern [i] ;392DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])) ;393Numeric->Upattern [i] = Fcpos [col] ;394}395}396397/* Fcpos no longer needed ] */398399/* ---------------------------------------------------------------------- */400/* convert L to the new pivot order */401/* ---------------------------------------------------------------------- */402403for (k = 0 ; k < n1 ; k++)404{405llen = Lilen [k] ;406DEBUG4 (("K "ID" New L. llen "ID" Singleton col\n", k, llen)) ;407if (llen > 0)408{409lp = Lip [k] ;410ip = (Int *) (Numeric->Memory + lp) ;411for (i = 0 ; i < llen ; i++)412{413row = *ip ;414DEBUG4 ((" old row "ID" new row "ID"\n", row, Frpos [row])) ;415ASSERT (row >= 0 && row < n_row) ;416*ip++ = Frpos [row] ;417}418}419}420421for (k = n1 ; k < npiv ; k++)422{423llen = Lilen [k] ;424DEBUG4 (("K "ID" New L. llen "ID" \n", k, llen)) ;425if (llen > 0)426{427lp = Lip [k] ;428if (lp < 0)429{430/* this starts a new Lchain */431lp = -lp ;432}433ip = (Int *) (Numeric->Memory + lp) ;434for (i = 0 ; i < llen ; i++)435{436row = *ip ;437DEBUG4 ((" old row "ID" new row "ID"\n", row, Frpos [row])) ;438ASSERT (row >= 0 && row < n_row) ;439*ip++ = Frpos [row] ;440}441}442}443444/* Frpos no longer needed ] */445446/* ---------------------------------------------------------------------- */447/* combine symbolic and numeric permutations */448/* ---------------------------------------------------------------------- */449450Cperm_init = Symbolic->Cperm_init ;451Rperm_init = Symbolic->Rperm_init ;452453for (k = 0 ; k < n_row ; k++)454{455Rperm [k] = Rperm_init [Rperm [k]] ;456}457458for (k = 0 ; k < n_col ; k++)459{460Cperm [k] = Cperm_init [Cperm [k]] ;461}462463/* Work object will be freed immediately upon return (to UMF_kernel */464/* and then to UMFPACK_numeric). */465}466467468