Rev 1820 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === UMFPACK_get_determinant ============================================== *//* ========================================================================== *//* -------------------------------------------------------------------------- *//* 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 *//* -------------------------------------------------------------------------- *//*User-callable. From the LU factors, scale factor, and permutation vectorsheld in the Numeric object, calculates the determinant of the matrix A.See umfpack_get_determinant.h for a more detailed description.Dynamic memory usage: calls UMF_malloc once, for a total space ofn integers, and then frees all of it via UMF_free when done.Contributed by David Bateman, Motorola, Nov. 2004.Modified for V4.4, Jan. 2005.*/#include "umf_internal.h"#include "umf_valid_numeric.h"#include "umf_malloc.h"#include "umf_free.h"/* ========================================================================== *//* === rescale_determinant ================================================== *//* ========================================================================== *//* If the mantissa is too big or too small, rescale it and change exponent */PRIVATE Int rescale_determinant(Entry *d_mantissa,double *d_exponent){double d_abs ;ABS (d_abs, *d_mantissa) ;if (SCALAR_IS_ZERO (d_abs)){/* the determinant is zero */*d_exponent = 0 ;return (FALSE) ;}if (SCALAR_IS_NAN (d_abs)){/* the determinant is NaN */return (FALSE) ;}while (d_abs < 1.){SCALE (*d_mantissa, 10.0) ;*d_exponent = *d_exponent - 1.0 ;ABS (d_abs, *d_mantissa) ;}while (d_abs >= 10.){SCALE (*d_mantissa, 0.1) ;*d_exponent = *d_exponent + 1.0 ;ABS (d_abs, *d_mantissa) ;}return (TRUE) ;}/* ========================================================================== *//* === UMFPACK_get_determinant ============================================== *//* ========================================================================== */GLOBAL Int UMFPACK_get_determinant(double *Mx,#ifdef COMPLEXdouble *Mz,#endifdouble *Ex,void *NumericHandle,double User_Info [UMFPACK_INFO]){/* ---------------------------------------------------------------------- *//* local variables *//* ---------------------------------------------------------------------- */Entry d_mantissa, d_tmp ;double d_exponent, Info2 [UMFPACK_INFO], one [2] = {1.0, 0.0}, d_sign ;Entry *D ;double *Info, *Rs ;NumericType *Numeric ;Int i, n, itmp, npiv, *Wi, *Rperm, *Cperm, do_scale ;#ifndef NRECIPROCALInt do_recip ;#endif/* ---------------------------------------------------------------------- *//* check input parameters *//* ---------------------------------------------------------------------- */if (User_Info != (double *) NULL){/* return Info in user's array */Info = User_Info ;}else{/* no Info array passed - use local one instead */Info = Info2 ;for (i = 0 ; i < UMFPACK_INFO ; i++){Info [i] = EMPTY ;}}Info [UMFPACK_STATUS] = UMFPACK_OK ;Numeric = (NumericType *) NumericHandle ;if (!UMF_valid_numeric (Numeric)){Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ;return (UMFPACK_ERROR_invalid_Numeric_object) ;}if (Numeric->n_row != Numeric->n_col){/* only square systems can be handled */Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_system ;return (UMFPACK_ERROR_invalid_system) ;}if (Mx == (double *) NULL){Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;return (UMFPACK_ERROR_argument_missing) ;}n = Numeric->n_row ;/* ---------------------------------------------------------------------- *//* allocate workspace *//* ---------------------------------------------------------------------- */Wi = (Int *) UMF_malloc (n, sizeof (Int)) ;if (!Wi){DEBUGm4 (("out of memory: get determinant\n")) ;Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;return (UMFPACK_ERROR_out_of_memory) ;}/* ---------------------------------------------------------------------- *//* compute the determinant *//* ---------------------------------------------------------------------- */Rs = Numeric->Rs ; /* row scale factors */do_scale = (Rs != (double *) NULL) ;#ifndef NRECIPROCALdo_recip = Numeric->do_recip ;#endifd_mantissa = ((Entry *) one) [0] ;d_exponent = 0.0 ;D = Numeric->D ;/* compute product of diagonal entries of U */for (i = 0 ; i < n ; i++){MULT (d_tmp, d_mantissa, D [i]) ;d_mantissa = d_tmp ;if (!rescale_determinant (&d_mantissa, &d_exponent)){/* the determinant is zero or NaN */Info [UMFPACK_STATUS] = UMFPACK_WARNING_singular_matrix ;/* no need to compute the determinant of R */do_scale = FALSE ;break ;}}/* compute product of diagonal entries of R (or its inverse) */if (do_scale){for (i = 0 ; i < n ; i++){#ifndef NRECIPROCALif (do_recip){/* compute determinant of R inverse */SCALE_DIV (d_mantissa, Rs [i]) ;}else#endif{/* compute determinant of R */SCALE (d_mantissa, Rs [i]) ;}if (!rescale_determinant (&d_mantissa, &d_exponent)){/* the determinant is zero or NaN. This is very unlikey to* occur here, since the scale factors for a tiny or zero row* are set to 1. */Info [UMFPACK_STATUS] = UMFPACK_WARNING_singular_matrix ;break ;}}}/* ---------------------------------------------------------------------- *//* determine if P and Q are odd or even permutations *//* ---------------------------------------------------------------------- */npiv = 0 ;Rperm = Numeric->Rperm ;for (i = 0 ; i < n ; i++){Wi [i] = Rperm [i] ;}for (i = 0 ; i < n ; i++){while (Wi [i] != i){itmp = Wi [Wi [i]] ;Wi [Wi [i]] = Wi [i] ;Wi [i] = itmp ;npiv++ ;}}Cperm = Numeric->Cperm ;for (i = 0 ; i < n ; i++){Wi [i] = Cperm [i] ;}for (i = 0 ; i < n ; i++){while (Wi [i] != i){itmp = Wi [Wi [i]] ;Wi [Wi [i]] = Wi [i] ;Wi [i] = itmp ;npiv++ ;}}/* if npiv is odd, the sign is -1. if it is even, the sign is +1 */d_sign = (npiv % 2) ? -1. : 1. ;/* ---------------------------------------------------------------------- *//* free workspace *//* ---------------------------------------------------------------------- */(void) UMF_free ((void *) Wi) ;/* ---------------------------------------------------------------------- *//* compute the magnitude and exponent of the determinant *//* ---------------------------------------------------------------------- */if (Ex == (double *) NULL){/* Ex is not provided, so return the entire determinant in d_mantissa */SCALE (d_mantissa, pow (10.0, d_exponent)) ;}else{Ex [0] = d_exponent ;}Mx [0] = d_sign * REAL_COMPONENT (d_mantissa) ;#ifdef COMPLEXif (SPLIT (Mz)){Mz [0] = d_sign * IMAG_COMPONENT (d_mantissa) ;}else{Mx [1] = d_sign * IMAG_COMPONENT (d_mantissa) ;}#endif/* determine if the determinant has (or will) overflow or underflow */if (d_exponent + 1.0 > log10 (DBL_MAX)){Info [UMFPACK_STATUS] = UMFPACK_WARNING_determinant_overflow ;}else if (d_exponent - 1.0 < log10 (DBL_MIN)){Info [UMFPACK_STATUS] = UMFPACK_WARNING_determinant_underflow ;}return (UMFPACK_OK) ;}