diff liboctave/UMFPACK/UMFPACK/Source/umfpack_numeric.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/umfpack_numeric.c	Fri Feb 25 19:55:28 2005 +0000
@@ -0,0 +1,792 @@
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* 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                       */
+/* -------------------------------------------------------------------------- */
+
+/*
+    User-callable.  Factorizes A into its LU factors, given a symbolic
+    pre-analysis computed by UMFPACK_symbolic.  See umfpack_numeric.h for a
+    description.
+
+    Dynamic memory allocation:  substantial.  See comments (1) through (7),
+    below.  If an error occurs, all allocated space is free'd by UMF_free.
+    If successful, the Numeric object contains 11 to 13 objects allocated by
+    UMF_malloc that hold the LU factors of the input matrix.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_set_stats.h"
+#include "umf_kernel.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_realloc.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+PRIVATE Int work_alloc
+(
+    WorkType *Work,
+    SymbolicType *Symbolic
+) ;
+
+PRIVATE void free_work
+(
+    WorkType *Work
+) ;
+
+PRIVATE Int numeric_alloc
+(
+    NumericType **NumericHandle,
+    SymbolicType *Symbolic,
+    double alloc_init,
+    Int scale
+) ;
+
+PRIVATE void error
+(
+    NumericType **Numeric,
+    WorkType *Work
+) ;
+
+
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_numeric
+(
+    const Int Ap [ ],
+    const Int Ai [ ],
+    const double Ax [ ],
+#ifdef COMPLEX
+    const double Az [ ],
+#endif
+    void *SymbolicHandle,
+    void **NumericHandle,
+    const double Control [UMFPACK_CONTROL],
+    double User_Info [UMFPACK_INFO]
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* local variables */
+    /* ---------------------------------------------------------------------- */
+
+    double Info2 [UMFPACK_INFO], alloc_init, relpt, relpt2, droptol,
+	front_alloc_init, stats [2] ;
+    double *Info ;
+    WorkType WorkSpace, *Work ;
+    NumericType *Numeric ;
+    SymbolicType *Symbolic ;
+    Int n_row, n_col, n_inner, newsize, i, status, *inew, npiv, ulen, scale ;
+    Unit *mnew ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the amount of time used by the process so far */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_tic (stats) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize and check inputs */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    UMF_dump_start ( ) ;
+    init_count = UMF_malloc_count ;
+    DEBUGm4 (("\nUMFPACK numeric: U transpose version\n")) ;
+#endif
+
+    /* If front_alloc_init negative then allocate that size of front in
+     * UMF_start_front.  If alloc_init negative, then allocate that initial
+     * size of Numeric->Memory. */
+
+    relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE,
+	UMFPACK_DEFAULT_PIVOT_TOLERANCE) ;
+    relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE,
+	UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ;
+    alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ;
+    front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT,
+	UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ;
+    scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+    droptol = GET_CONTROL (UMFPACK_DROPTOL, UMFPACK_DEFAULT_DROPTOL) ;
+
+    relpt   = MAX (0.0, MIN (relpt,  1.0)) ;
+    relpt2  = MAX (0.0, MIN (relpt2, 1.0)) ;
+    droptol = MAX (0.0, droptol) ;
+    front_alloc_init = MIN (1.0, front_alloc_init) ;
+
+    if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX)
+    {
+	scale = UMFPACK_DEFAULT_SCALE ;
+    }
+
+    if (User_Info != (double *) NULL)
+    {
+	/* return Info in user's array */
+	Info = User_Info ;
+	/* clear the parts of Info that are set by UMFPACK_numeric */
+	for (i = UMFPACK_NUMERIC_SIZE ; i <= UMFPACK_MAX_FRONT_NCOLS ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+	for (i = UMFPACK_NUMERIC_DEFRAG ; i < UMFPACK_IR_TAKEN ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+    }
+    else
+    {
+	/* no Info array passed - use local one instead */
+	Info = Info2 ;
+	for (i = 0 ; i < UMFPACK_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+    }
+
+    Symbolic = (SymbolicType *) SymbolicHandle ;
+    Numeric = (NumericType *) NULL ;
+    if (!UMF_valid_symbolic (Symbolic))
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Symbolic_object ;
+	return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+    }
+
+    /* compute alloc_init automatically for AMD ordering */
+    if (Symbolic->ordering == UMFPACK_ORDERING_AMD && alloc_init >= 0)
+    {
+	alloc_init = (Symbolic->nz + Symbolic->amd_lunz) / Symbolic->lunz_bound;
+	alloc_init = MIN (1.0, alloc_init) ;
+	alloc_init *= UMF_REALLOC_INCREASE ;
+    }
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+
+    /* check for integer overflow in Numeric->Memory minimum size */
+    if (INT_OVERFLOW (Symbolic->dnum_mem_init_usage * sizeof (Unit)))
+    {
+	/* :: int overflow, initial Numeric->Memory size :: */
+	/* There's no hope to allocate a Numeric object big enough simply to
+	 * hold the initial matrix, so return an out-of-memory condition */
+	DEBUGm4 (("out of memory: numeric int overflow\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+
+    Info [UMFPACK_STATUS] = UMFPACK_OK ;
+    Info [UMFPACK_NROW] = n_row ;
+    Info [UMFPACK_NCOL] = n_col ;
+    Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ;
+
+    if (!Ap || !Ai || !Ax || !NumericHandle)
+    {
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+	return (UMFPACK_ERROR_argument_missing) ;
+    }
+
+    Info [UMFPACK_NZ] = Ap [n_col] ;
+    *NumericHandle = (void *) NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the Work object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (1) calls UMF_malloc 15 or 17 times, to obtain temporary workspace of
+     * size c+1 Entry's and 2*(n_row+1) + 3*(n_col+1) + (n_col+n_inner+1) +
+     * (nn+1) + * 3*(c+1) + 2*(r+1) + max(r,c) + (nfr+1) integers plus 2*nn
+     * more integers if diagonal pivoting is to be done.  r is the maximum
+     * number of rows in any frontal matrix, c is the maximum number of columns
+     * in any frontal matrix, n_inner is min (n_row,n_col), nn is
+     * max (n_row,n_col), and nfr is the number of frontal matrices.  For a
+     * square matrix, this is c+1 Entry's and about 8n + 3c + 2r + max(r,c) +
+     * nfr integers, plus 2n more for diagonal pivoting.
+     */
+
+    Work = &WorkSpace ;
+    Work->n_row = n_row ;
+    Work->n_col = n_col ;
+    Work->nfr = Symbolic->nfr ;
+    Work->nb = Symbolic->nb ;
+    Work->n1 = Symbolic->n1 ;
+
+    if (!work_alloc (Work, Symbolic))
+    {
+	DEBUGm4 (("out of memory: numeric work\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	error (&Numeric, Work) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    ASSERT (UMF_malloc_count == init_count + 16 + 2*Symbolic->prefer_diagonal) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate Numeric object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (2) calls UMF_malloc 10 or 11 times, for a total space of
+     * sizeof (NumericType) bytes, 4*(n_row+1) + 4*(n_row+1) integers, and
+     * (n_inner+1) Entry's, plus n_row Entry's if row scaling is to be done.
+     * sizeof (NumericType) is a small constant.  Next, it calls UMF_malloc
+     * once, for the variable-sized part of the Numeric object
+     * (Numeric->Memory).  The size of this object is the larger of
+     * (Control [UMFPACK_ALLOC_INIT]) *  (the approximate upper bound computed
+     * by UMFPACK_symbolic), and the minimum required to start the numerical
+     * factorization.  * This request is reduced if it fails.
+     */
+
+    if (!numeric_alloc (&Numeric, Symbolic, alloc_init, scale))
+    {
+	DEBUGm4 (("out of memory: initial numeric\n")) ;
+	Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+	error (&Numeric, Work) ;
+	return (UMFPACK_ERROR_out_of_memory) ;
+    }
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+    ASSERT (UMF_malloc_count == init_count
+	+ (16 + 2*Symbolic->prefer_diagonal)
+	+ (11 + (scale != UMFPACK_SCALE_NONE))) ;
+
+    /* set control parameters */
+    Numeric->relpt = relpt ;
+    Numeric->relpt2 = relpt2 ;
+    Numeric->droptol = droptol ;
+    Numeric->alloc_init = alloc_init ;
+    Numeric->front_alloc_init = front_alloc_init ;
+    Numeric->scale = scale ;
+
+    DEBUG0 (("umf relpt %g %g init %g %g inc %g red %g\n",
+	relpt, relpt2, alloc_init, front_alloc_init,
+	UMF_REALLOC_INCREASE, UMF_REALLOC_REDUCTION)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* scale and factorize */
+    /* ---------------------------------------------------------------------- */
+
+    /* (3) During numerical factorization (inside UMF_kernel), the variable-size
+     * block of memory is increased in size via a call to UMF_realloc if it is
+     * found to be too small.  During factorization, this block holds the
+     * pattern and values of L and U at the top end, and the elements
+     * (contibution blocks) and the current frontal matrix (Work->F*) at the
+     * bottom end.  The peak size of the variable-sized object is estimated in
+     * UMFPACK_*symbolic (Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]), although this
+     * upper bound can be very loose.  The size of the Symbolic object
+     * (which is currently allocated) is in Info [UMFPACK_SYMBOLIC_SIZE], and
+     * is between 2*n and 13*n integers.
+     */
+
+    DEBUG0 (("Calling umf_kernel\n")) ;
+    status = UMF_kernel (Ap, Ai, Ax,
+#ifdef COMPLEX
+	Az,
+#endif
+	Numeric, Work, Symbolic) ;
+
+    Info [UMFPACK_STATUS] = status ;
+    if (status < UMFPACK_OK)
+    {
+	/* out of memory, or pattern has changed */
+	error (&Numeric, Work) ;
+	return (status) ;
+    }
+
+    Info [UMFPACK_FORCED_UPDATES] = Work->nforced ;
+    Info [UMFPACK_VARIABLE_INIT] = Numeric->init_usage ;
+    if (Symbolic->prefer_diagonal)
+    {
+	Info [UMFPACK_NOFF_DIAG] = Work->noff_diagonal ;
+    }
+
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+
+    npiv = Numeric->npiv ;	/* = n_inner for nonsingular matrices */
+    ulen = Numeric->ulen ;	/* = 0 for square nonsingular matrices */
+
+    /* ---------------------------------------------------------------------- */
+    /* free Work object */
+    /* ---------------------------------------------------------------------- */
+
+    /* (4) After numerical factorization all of the objects allocated in step
+     * (1) are freed via UMF_free, except that one object of size n_col+1 is
+     * kept if there are off-diagonal nonzeros in the last pivot row (can only
+     * occur for singular or rectangular matrices).  This is Work->Upattern,
+     * which is transfered to Numeric->Upattern if ulen > 0.
+     */
+
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+
+    free_work (Work) ;
+
+    DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+	init_count, UMF_malloc_count)) ;
+    DEBUG0 (("Numeric->ulen: "ID" scale: "ID"\n", ulen, scale)) ;
+    ASSERT (UMF_malloc_count == init_count + (ulen > 0) +
+	(11 + (scale != UMFPACK_SCALE_NONE))) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce Lpos, Lilen, Lip, Upos, Uilen and Uip to size npiv+1 */
+    /* ---------------------------------------------------------------------- */
+
+    /* (5) Six components of the Numeric object are reduced in size if the
+     * matrix is singular or rectangular.   The original size is 3*(n_row+1) +
+     * 3*(n_col+1) integers.  The new size is 6*(npiv+1) integers.  For
+     * square non-singular matrices, these two sizes are the same.
+     */
+
+    if (npiv < n_row)
+    {
+	/* reduce Lpos, Uilen, and Uip from size n_row+1 to size npiv */
+	inew = (Int *) UMF_realloc (Numeric->Lpos, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Lpos = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Uilen, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Uilen = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Uip, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Uip = inew ;
+	}
+    }
+
+    if (npiv < n_col)
+    {
+	/* reduce Upos, Lilen, and Lip from size n_col+1 to size npiv */
+	inew = (Int *) UMF_realloc (Numeric->Upos, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Upos = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Lilen, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Lilen = inew ;
+	}
+	inew = (Int *) UMF_realloc (Numeric->Lip, npiv+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Lip = inew ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce Numeric->Upattern from size n_col+1 to size ulen+1 */
+    /* ---------------------------------------------------------------------- */
+
+    /* (6) The size of Numeric->Upattern (formerly Work->Upattern) is reduced
+     * from size n_col+1 to size ulen + 1.  If ulen is zero, the object does
+     * not exist. */
+
+    DEBUG4 (("ulen: "ID" Upattern "ID"\n", ulen, (Int) Numeric->Upattern)) ;
+    ASSERT (IMPLIES (ulen == 0, Numeric->Upattern == (Int *) NULL)) ;
+    if (ulen > 0 && ulen < n_col)
+    {
+	inew = (Int *) UMF_realloc (Numeric->Upattern, ulen+1, sizeof (Int)) ;
+	if (inew)
+	{
+	    Numeric->Upattern = inew ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce Numeric->Memory to hold just the LU factors at the head */
+    /* ---------------------------------------------------------------------- */
+
+    /* (7) The variable-sized block (Numeric->Memory) is reduced to hold just L
+     * and U, via a call to UMF_realloc, since the frontal matrices are no
+     * longer needed.
+     */
+
+    newsize = Numeric->ihead ;
+    if (newsize < Numeric->size)
+    {
+	mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ;
+	if (mnew)
+	{
+	    /* realloc succeeded (how can it fail since the size is reduced?) */
+	    Numeric->Memory = mnew ;
+	    Numeric->size = newsize ;
+	}
+    }
+    Numeric->ihead = Numeric->size ;
+    Numeric->itail = Numeric->ihead ;
+    Numeric->tail_usage = 0 ;
+    Numeric->ibig = EMPTY ;
+    /* UMF_mem_alloc_tail_block can no longer be called (no tail marker) */
+
+    /* ---------------------------------------------------------------------- */
+    /* report the results and return the Numeric object */
+    /* ---------------------------------------------------------------------- */
+
+    UMF_set_stats (
+	Info,
+	Symbolic,
+	(double) Numeric->max_usage,	/* actual peak Numeric->Memory */
+	(double) Numeric->size,		/* actual final Numeric->Memory */
+	Numeric->flops,			/* actual "true flops" */
+	(double) Numeric->lnz + n_inner,		/* actual nz in L */
+	(double) Numeric->unz + Numeric->nnzpiv,	/* actual nz in U */
+	(double) Numeric->maxfrsize,	/* actual largest front size */
+	(double) ulen,			/* actual Numeric->Upattern size */
+	(double) npiv,			/* actual # pivots found */
+	(double) Numeric->maxnrows,	/* actual largest #rows in front */
+	(double) Numeric->maxncols,	/* actual largest #cols in front */
+	scale != UMFPACK_SCALE_NONE,
+	Symbolic->prefer_diagonal,
+	ACTUAL) ;
+
+    Info [UMFPACK_ALLOC_INIT_USED] = Numeric->alloc_init ;
+    Info [UMFPACK_NUMERIC_DEFRAG] = Numeric->ngarbage ;
+    Info [UMFPACK_NUMERIC_REALLOC] = Numeric->nrealloc ;
+    Info [UMFPACK_NUMERIC_COSTLY_REALLOC] = Numeric->ncostly ;
+    Info [UMFPACK_COMPRESSED_PATTERN] = Numeric->isize ;
+    Info [UMFPACK_LU_ENTRIES] = Numeric->nLentries + Numeric->nUentries +
+	    Numeric->npiv ;
+    Info [UMFPACK_UDIAG_NZ] = Numeric->nnzpiv ;
+    Info [UMFPACK_RSMIN] = Numeric->rsmin ;
+    Info [UMFPACK_RSMAX] = Numeric->rsmax ;
+    Info [UMFPACK_WAS_SCALED] = Numeric->scale ;
+
+    /* nz in L and U with no dropping of small entries */
+    Info [UMFPACK_ALL_LNZ] = Numeric->all_lnz + n_inner ;
+    Info [UMFPACK_ALL_UNZ] = Numeric->all_unz + Numeric->nnzpiv ;
+    Info [UMFPACK_NZDROPPED] =
+	  (Numeric->all_lnz - Numeric->lnz)
+	+ (Numeric->all_unz - Numeric->unz) ;
+
+    /* estimate of the reciprocal of the condition number. */
+    if (SCALAR_IS_ZERO (Numeric->min_udiag)
+     || SCALAR_IS_ZERO (Numeric->max_udiag)
+     ||	SCALAR_IS_NAN (Numeric->min_udiag)
+     ||	SCALAR_IS_NAN (Numeric->max_udiag))
+    {
+	/* rcond is zero if there is any zero or NaN on the diagonal */
+	Numeric->rcond = 0.0 ;
+    }
+    else
+    {
+	/* estimate of the recipricol of the condition number. */
+	/* This is NaN if diagonal is zero-free, but has one or more NaN's. */
+	Numeric->rcond = Numeric->min_udiag / Numeric->max_udiag ;
+    }
+    Info [UMFPACK_UMIN]  = Numeric->min_udiag ;
+    Info [UMFPACK_UMAX]  = Numeric->max_udiag ;
+    Info [UMFPACK_RCOND] = Numeric->rcond ;
+
+    if (Numeric->nnzpiv < n_inner
+    || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+    {
+	/* there are zeros and/or NaN's on the diagonal of U */
+	DEBUG0 (("Warning, matrix is singular in umfpack_numeric\n")) ;
+	DEBUG0 (("nnzpiv "ID" n_inner "ID" rcond %g\n", Numeric->nnzpiv,
+	    n_inner, Numeric->rcond)) ;
+	status = UMFPACK_WARNING_singular_matrix ;
+	Info [UMFPACK_STATUS] = status ;
+    }
+
+    Numeric->valid = NUMERIC_VALID ;
+    *NumericHandle = (void *) Numeric ;
+
+    /* Numeric has 11 to 13 objects */
+    ASSERT (UMF_malloc_count == init_count + 11 +
+	+ (ulen > 0)			    /* Numeric->Upattern */
+	+ (scale != UMFPACK_SCALE_NONE)) ;  /* Numeric->Rs */
+
+    /* ---------------------------------------------------------------------- */
+    /* get the time used by UMFPACK_numeric */
+    /* ---------------------------------------------------------------------- */
+
+    umfpack_toc (stats) ;
+    Info [UMFPACK_NUMERIC_WALLTIME] = stats [0] ;
+    Info [UMFPACK_NUMERIC_TIME] = stats [1] ;
+
+    /* return UMFPACK_OK or UMFPACK_WARNING_singular_matrix */
+    return (status) ;
+
+}
+
+
+/* ========================================================================== */
+/* === numeric_alloc ======================================================== */
+/* ========================================================================== */
+
+/* Allocate the Numeric object */
+
+PRIVATE Int numeric_alloc
+(
+    NumericType **NumericHandle,
+    SymbolicType *Symbolic,
+    double alloc_init,
+    Int scale
+)
+{
+    double nsize, bsize ;
+    Int n_row, n_col, n_inner, min_usage, trying ;
+    NumericType *Numeric ;
+
+    DEBUG0 (("numeric alloc:\n")) ;
+
+    n_row = Symbolic->n_row ;
+    n_col = Symbolic->n_col ;
+    n_inner = MIN (n_row, n_col) ;
+    *NumericHandle = (NumericType *) NULL ;
+
+    /* 1 allocation:  accounted for in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ;
+
+    if (!Numeric)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+    Numeric->valid = 0 ;
+    *NumericHandle = Numeric ;
+
+    /* 9 allocations:  accounted for in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    Numeric->D = (Entry *) UMF_malloc (n_inner+1, sizeof (Entry)) ;
+    Numeric->Rperm = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Cperm = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Lpos = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Lilen = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Lip = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Upos = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+    Numeric->Uilen = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+    Numeric->Uip = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+
+    /* 1 allocation if scaling:  in UMF_set_stats (num_On_size1),
+     * free'd in umfpack_free_numeric */
+    if (scale != UMFPACK_SCALE_NONE)
+    {
+	DEBUG0 (("Allocating scale factors\n")) ;
+	Numeric->Rs = (double *) UMF_malloc (n_row, sizeof (double)) ;
+    }
+    else
+    {
+	DEBUG0 (("No scale factors allocated (R = I)\n")) ;
+	Numeric->Rs = (double *) NULL ;
+    }
+
+    Numeric->Memory = (Unit *) NULL ;
+
+    /* Upattern has already been allocated as part of the Work object.  If
+     * the matrix is singular or rectangular, and there are off-diagonal
+     * nonzeros in the last pivot row, then Work->Upattern is not free'd.
+     * Instead it is transfered to Numeric->Upattern.  If it exists,
+     * Numeric->Upattern is free'd in umfpack_free_numeric. */
+    Numeric->Upattern = (Int *) NULL ;	/* used for singular matrices only */
+
+    if (!Numeric->D || !Numeric->Rperm || !Numeric->Cperm || !Numeric->Upos ||
+	!Numeric->Lpos || !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip ||
+	!Numeric->Uip || (scale != UMFPACK_SCALE_NONE && !Numeric->Rs))
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate initial Numeric->Memory for LU factors and elements */
+    /* ---------------------------------------------------------------------- */
+
+    if (alloc_init < 0)
+    {
+	/* -alloc_init is the exact size to initially allocate */
+	nsize = -alloc_init ;
+    }
+    else
+    {
+	/* alloc_init is a ratio of the upper bound memory usage */
+	nsize = (alloc_init * Symbolic->num_mem_usage_est) + 1 ;
+    }
+    min_usage = Symbolic->num_mem_init_usage ;
+
+    /* Numeric->Memory must be large enough for UMF_kernel_init */
+    nsize = MAX (min_usage, nsize) ;
+
+    /* Numeric->Memory cannot be larger in size than Int_MAX / sizeof(Unit) */
+    /* For ILP32 mode:  2GB (nsize cannot be bigger than 256 Mwords) */
+    bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
+    DEBUG0 (("bsize %g\n", bsize)) ;
+    nsize = MIN (nsize, bsize) ;
+
+    Numeric->size = (Int) nsize ;
+
+    DEBUG0 (("Num init %g usage_est %g numsize "ID" minusage "ID"\n",
+	alloc_init, Symbolic->num_mem_usage_est, Numeric->size, min_usage)) ;
+
+    /* allocates 1 object: */
+    /* keep trying until successful, or memory request is too small */
+    trying = TRUE ;
+    while (trying)
+    {
+	Numeric->Memory = (Unit *) UMF_malloc (Numeric->size, sizeof (Unit)) ;
+	if (Numeric->Memory)
+	{
+	    DEBUG0 (("Successful Numeric->size: "ID"\n", Numeric->size)) ;
+	    return (TRUE) ;
+	}
+	/* too much, reduce the request (but not below the minimum) */
+	/* and try again */
+	trying = Numeric->size > min_usage ;
+	Numeric->size = (Int)
+	    (UMF_REALLOC_REDUCTION * ((double) Numeric->size)) ;
+	Numeric->size = MAX (min_usage, Numeric->size) ;
+    }
+
+    return (FALSE) ;	/* we failed to allocate Numeric->Memory */
+}
+
+
+/* ========================================================================== */
+/* === work_alloc =========================================================== */
+/* ========================================================================== */
+
+/* Allocate the Work object.  Return TRUE if successful. */
+
+PRIVATE Int work_alloc
+(
+    WorkType *Work,
+    SymbolicType *Symbolic
+)
+{
+    Int n_row, n_col, nn, maxnrows, maxncols, nfr, ok, maxnrc, n1 ;
+
+    n_row = Work->n_row ;
+    n_col = Work->n_col ;
+    nn = MAX (n_row, n_col) ;
+    nfr = Work->nfr ;
+    n1 = Symbolic->n1 ;
+    ASSERT (n1 <= n_row && n1 <= n_col) ;
+
+    maxnrows = Symbolic->maxnrows + Symbolic->nb ;
+    maxnrows = MIN (n_row, maxnrows) ;
+    maxncols = Symbolic->maxncols + Symbolic->nb ;
+    maxncols = MIN (n_col, maxncols) ;
+    maxnrc = MAX (maxnrows, maxncols) ;
+
+    DEBUG0 (("work alloc:  maxnrows+nb "ID" maxncols+nb "ID"\n",
+	maxnrows, maxncols)) ;
+
+    /* 15 allocations, freed in free_work: */
+    /* accounted for in UMF_set_stats (work_usage) */
+    Work->Wx = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+    Work->Wy = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+    Work->Frpos    = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+    Work->Lpattern = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+    Work->Fcpos = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    Work->Wp = (Int *) UMF_malloc (nn + 1, sizeof (Int)) ;
+    Work->Wrp = (Int *) UMF_malloc (MAX (n_col,maxnrows) + 1, sizeof (Int)) ;
+    Work->Frows = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+    Work->Wm    = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+    Work->Fcols = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Wio   = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Woi   = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+    Work->Woo = (Int *) UMF_malloc (maxnrc + 1, sizeof (Int));
+    Work->elen = (n_col - n1) + (n_row - n1) + MIN (n_col-n1, n_row-n1) + 1 ;
+    Work->E = (Int *) UMF_malloc (Work->elen, sizeof (Int)) ;
+    Work->Front_new1strow = (Int *) UMF_malloc (nfr + 1, sizeof (Int)) ;
+
+    ok = (Work->Frpos && Work->Fcpos && Work->Lpattern
+	&& Work->Wp && Work->Wrp && Work->Frows && Work->Fcols
+	&& Work->Wio && Work->Woi && Work->Woo && Work->Wm
+	&& Work->E && Work->Front_new1strow && Work->Wx && Work->Wy) ;
+
+    /* 2 allocations: accounted for in UMF_set_stats (work_usage) */
+    if (Symbolic->prefer_diagonal)
+    {
+	Work->Diagonal_map  = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+	Work->Diagonal_imap = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+	ok = ok && Work->Diagonal_map && Work->Diagonal_imap ;
+    }
+    else
+    {
+	/* no diagonal map needed for rectangular matrices */
+	Work->Diagonal_map = (Int *) NULL ;
+	Work->Diagonal_imap = (Int *) NULL ;
+    }
+
+    /* 1 allocation, may become part of Numeric (if singular or rectangular): */
+    Work->Upattern = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+    ok = ok && Work->Upattern ;
+
+    /* current frontal matrix does not yet exist */
+    Work->Flublock = (Entry *) NULL ;
+    Work->Flblock  = (Entry *) NULL ;
+    Work->Fublock  = (Entry *) NULL ;
+    Work->Fcblock  = (Entry *) NULL ;
+
+    DEBUG0 (("work alloc done.\n")) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+    WorkType *Work
+)
+{
+    DEBUG0 (("work free:\n")) ;
+    if (Work)
+    {
+	/* these 16 objects do exist */
+	Work->Wx = (Entry *) UMF_free ((void *) Work->Wx) ;
+	Work->Wy = (Entry *) UMF_free ((void *) Work->Wy) ;
+	Work->Frpos = (Int *) UMF_free ((void *) Work->Frpos) ;
+	Work->Fcpos = (Int *) UMF_free ((void *) Work->Fcpos) ;
+	Work->Lpattern = (Int *) UMF_free ((void *) Work->Lpattern) ;
+	Work->Upattern = (Int *) UMF_free ((void *) Work->Upattern) ;
+	Work->Wp = (Int *) UMF_free ((void *) Work->Wp) ;
+	Work->Wrp = (Int *) UMF_free ((void *) Work->Wrp) ;
+	Work->Frows = (Int *) UMF_free ((void *) Work->Frows) ;
+	Work->Fcols = (Int *) UMF_free ((void *) Work->Fcols) ;
+	Work->Wio = (Int *) UMF_free ((void *) Work->Wio) ;
+	Work->Woi = (Int *) UMF_free ((void *) Work->Woi) ;
+	Work->Woo = (Int *) UMF_free ((void *) Work->Woo) ;
+	Work->Wm = (Int *) UMF_free ((void *) Work->Wm) ;
+	Work->E = (Int *) UMF_free ((void *) Work->E) ;
+	Work->Front_new1strow =
+	    (Int *) UMF_free ((void *) Work->Front_new1strow) ;
+
+	/* these objects might not exist */
+	Work->Diagonal_map = (Int *) UMF_free ((void *) Work->Diagonal_map) ;
+	Work->Diagonal_imap = (Int *) UMF_free ((void *) Work->Diagonal_imap) ;
+    }
+    DEBUG0 (("work free done.\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_numeric.  Free all allocated memory. */
+
+PRIVATE void error
+(
+    NumericType **Numeric,
+    WorkType *Work
+)
+{
+    free_work (Work) ;
+    UMFPACK_free_numeric ((void **) Numeric) ;
+    ASSERT (UMF_malloc_count == init_count) ;
+}