Rev 1820 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === UMF_utsolve ========================================================== *//* ========================================================================== *//* -------------------------------------------------------------------------- *//* UMFPACK Version 4.5, 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 *//* -------------------------------------------------------------------------- *//* solves U'x = b or U.'x=b, where U is the upper triangular factor of a *//* matrix. B is overwritten with the solution X. *//* Returns the floating point operation count */#include "umf_internal.h"GLOBAL double#ifdef CONJUGATE_SOLVEUMF_uhsolve /* solve U'x=b (complex conjugate transpose) */#elseUMF_utsolve /* solve U.'x=b (array transpose) */#endif(NumericType *Numeric,Entry X [ ], /* b on input, solution x on output */Int Pattern [ ] /* a work array of size n */){/* ---------------------------------------------------------------------- *//* local variables *//* ---------------------------------------------------------------------- */Entry xk ;Entry *xp, *D, *Uval ;Int k, deg, j, *ip, col, *Upos, *Uilen, kstart, kend, up,*Uip, n, uhead, ulen, pos, npiv, n1, *Ui ;/* ---------------------------------------------------------------------- *//* get parameters *//* ---------------------------------------------------------------------- */if (Numeric->n_row != Numeric->n_col) return (0.) ;n = Numeric->n_row ;npiv = Numeric->npiv ;Upos = Numeric->Upos ;Uilen = Numeric->Uilen ;Uip = Numeric->Uip ;D = Numeric->D ;kend = 0 ;n1 = Numeric->n1 ;#ifndef NDEBUGDEBUG4 (("Utsolve start: npiv "ID" n "ID"\n", npiv, n)) ;for (j = 0 ; j < n ; j++){DEBUG4 (("Utsolve start "ID": ", j)) ;EDEBUG4 (X [j]) ;DEBUG4 (("\n")) ;}#endif/* ---------------------------------------------------------------------- *//* singletons *//* ---------------------------------------------------------------------- */for (k = 0 ; k < n1 ; k++){DEBUG4 (("Singleton k "ID"\n", k)) ;#ifndef NO_DIVIDE_BY_ZERO/* Go ahead and divide by zero if D [k] is zero. */#ifdef CONJUGATE_SOLVE/* xk = X [k] / conjugate (D [k]) ; */DIV_CONJ (xk, X [k], D [k]) ;#else/* xk = X [k] / D [k] ; */DIV (xk, X [k], D [k]) ;#endif#else/* Do not divide by zero */if (IS_NONZERO (D [k])){#ifdef CONJUGATE_SOLVE/* xk = X [k] / conjugate (D [k]) ; */DIV_CONJ (xk, X [k], D [k]) ;#else/* xk = X [k] / D [k] ; */DIV (xk, X [k], D [k]) ;#endif}#endifX [k] = xk ;deg = Uilen [k] ;if (deg > 0 && IS_NONZERO (xk)){up = Uip [k] ;Ui = (Int *) (Numeric->Memory + up) ;up += UNITS (Int, deg) ;Uval = (Entry *) (Numeric->Memory + up) ;for (j = 0 ; j < deg ; j++){DEBUG4 ((" k "ID" col "ID" value", k, Ui [j])) ;EDEBUG4 (Uval [j]) ;DEBUG4 (("\n")) ;#ifdef CONJUGATE_SOLVE/* X [Ui [j]] -= xk * conjugate (Uval [j]) ; */MULT_SUB_CONJ (X [Ui [j]], xk, Uval [j]) ;#else/* X [Ui [j]] -= xk * Uval [j] ; */MULT_SUB (X [Ui [j]], xk, Uval [j]) ;#endif}}}/* ---------------------------------------------------------------------- *//* nonsingletons *//* ---------------------------------------------------------------------- */for (kstart = n1 ; kstart < npiv ; kstart = kend + 1){/* ------------------------------------------------------------------ *//* find the end of this Uchain *//* ------------------------------------------------------------------ */DEBUG4 (("kstart "ID" kend "ID"\n", kstart, kend)) ;/* for (kend = kstart ; kend < npiv && Uip [kend+1] > 0 ; kend++) ; */kend = kstart ;while (kend < npiv && Uip [kend+1] > 0){kend++ ;}/* ------------------------------------------------------------------ *//* scan the whole Uchain to find the pattern of the first row of U *//* ------------------------------------------------------------------ */k = kend+1 ;DEBUG4 (("\nKend "ID" K "ID"\n", kend, k)) ;/* ------------------------------------------------------------------ *//* start with last row in Uchain of U in Pattern [0..deg-1] *//* ------------------------------------------------------------------ */if (k == npiv){deg = Numeric->ulen ;if (deg > 0){/* :: make last pivot row of U (singular matrices only) :: */for (j = 0 ; j < deg ; j++){Pattern [j] = Numeric->Upattern [j] ;}}}else{ASSERT (k >= 0 && k < npiv) ;up = -Uip [k] ;ASSERT (up > 0) ;deg = Uilen [k] ;DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ;ip = (Int *) (Numeric->Memory + up) ;for (j = 0 ; j < deg ; j++){col = *ip++ ;DEBUG4 ((" k "ID" col "ID"\n", k-1, col)) ;ASSERT (k <= col) ;Pattern [j] = col ;}}/* empty the stack at the bottom of Pattern */uhead = n ;for (k = kend ; k > kstart ; k--){/* Pattern [0..deg-1] is the pattern of row k of U *//* -------------------------------------------------------------- *//* make row k-1 of U in Pattern [0..deg-1] *//* -------------------------------------------------------------- */ASSERT (k >= 0 && k < npiv) ;ulen = Uilen [k] ;/* delete, and push on the stack */for (j = 0 ; j < ulen ; j++){ASSERT (uhead >= deg) ;Pattern [--uhead] = Pattern [--deg] ;}DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k, deg)) ;ASSERT (deg >= 0) ;pos = Upos [k] ;if (pos != EMPTY){/* add the pivot column */DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;ASSERT (pos >= 0 && pos <= deg) ;Pattern [deg++] = Pattern [pos] ;Pattern [pos] = k ;}}/* Pattern [0..deg-1] is now the pattern of the first row in Uchain *//* ------------------------------------------------------------------ *//* solve using this Uchain, in reverse order *//* ------------------------------------------------------------------ */DEBUG4 (("Unwinding Uchain\n")) ;for (k = kstart ; k <= kend ; k++){/* -------------------------------------------------------------- *//* construct row k *//* -------------------------------------------------------------- */ASSERT (k >= 0 && k < npiv) ;pos = Upos [k] ;if (pos != EMPTY){/* remove the pivot column */DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ;ASSERT (k > kstart) ;ASSERT (pos >= 0 && pos < deg) ;ASSERT (Pattern [pos] == k) ;Pattern [pos] = Pattern [--deg] ;}up = Uip [k] ;ulen = Uilen [k] ;if (k > kstart){/* concatenate the deleted pattern; pop from the stack */for (j = 0 ; j < ulen ; j++){ASSERT (deg <= uhead && uhead < n) ;Pattern [deg++] = Pattern [uhead++] ;}DEBUG4 (("middle of chain, row of U "ID" deg "ID"\n", k, deg)) ;ASSERT (deg >= 0) ;}/* -------------------------------------------------------------- *//* use row k of U *//* -------------------------------------------------------------- */#ifndef NO_DIVIDE_BY_ZERO/* Go ahead and divide by zero if D [k] is zero. */#ifdef CONJUGATE_SOLVE/* xk = X [k] / conjugate (D [k]) ; */DIV_CONJ (xk, X [k], D [k]) ;#else/* xk = X [k] / D [k] ; */DIV (xk, X [k], D [k]) ;#endif#else/* Do not divide by zero */if (IS_NONZERO (D [k])){#ifdef CONJUGATE_SOLVE/* xk = X [k] / conjugate (D [k]) ; */DIV_CONJ (xk, X [k], D [k]) ;#else/* xk = X [k] / D [k] ; */DIV (xk, X [k], D [k]) ;#endif}#endifX [k] = xk ;if (IS_NONZERO (xk)){if (k == kstart){up = -up ;xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;}else{xp = (Entry *) (Numeric->Memory + up) ;}for (j = 0 ; j < deg ; j++){DEBUG4 ((" k "ID" col "ID" value", k, Pattern [j])) ;EDEBUG4 (*xp) ;DEBUG4 (("\n")) ;#ifdef CONJUGATE_SOLVE/* X [Pattern [j]] -= xk * conjugate (*xp) ; */MULT_SUB_CONJ (X [Pattern [j]], xk, *xp) ;#else/* X [Pattern [j]] -= xk * (*xp) ; */MULT_SUB (X [Pattern [j]], xk, *xp) ;#endifxp++ ;}}}ASSERT (uhead == n) ;}#ifndef NO_DIVIDE_BY_ZEROfor (k = npiv ; k < n ; k++){/* This is an *** intentional *** divide-by-zero, to get Inf or Nan,* as appropriate. It is not a bug. */ASSERT (IS_ZERO (D [k])) ;/* For conjugate solve, D [k] == conjugate (D [k]), in this case *//* xk = X [k] / D [k] ; */DIV (xk, X [k], D [k]) ;X [k] = xk ;}#endif#ifndef NDEBUGfor (j = 0 ; j < n ; j++){DEBUG4 (("Utsolve done "ID": ", j)) ;EDEBUG4 (X [j]) ;DEBUG4 (("\n")) ;}DEBUG4 (("Utsolve done.\n")) ;#endifreturn (DIV_FLOPS * ((double) n) + MULTSUB_FLOPS * ((double) Numeric->unz));}