Mercurial > octave-nkf
diff liboctave/UMFPACK/UMFPACK/Source/umf_grow_front.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_grow_front.c Fri Feb 25 19:55:28 2005 +0000 @@ -0,0 +1,293 @@ +/* ========================================================================== */ +/* === UMF_grow_front ======================================================= */ +/* ========================================================================== */ + +/* -------------------------------------------------------------------------- */ +/* 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 */ +/* -------------------------------------------------------------------------- */ + +/* Current frontal matrix is too small. Make it bigger. */ + +#include "umf_internal.h" +#include "umf_mem_free_tail_block.h" +#include "umf_mem_alloc_tail_block.h" +#include "umf_get_memory.h" + +GLOBAL Int UMF_grow_front +( + NumericType *Numeric, + Int fnr2, /* desired size is fnr2-by-fnc2 */ + Int fnc2, + WorkType *Work, + Int do_what /* -1: UMF_start_front + * 0: UMF_init_front, do not recompute Fcpos + * 1: UMF_extend_front + * 2: UMF_init_front, recompute Fcpos */ +) +{ + /* ---------------------------------------------------------------------- */ + /* local variables */ + /* ---------------------------------------------------------------------- */ + + double s ; + Entry *Fcold, *Fcnew ; + Int j, i, col, *Fcpos, *Fcols, fnrows_max, fncols_max, fnr_curr, nb, + fnrows_new, fncols_new, fnr_min, fnc_min, minsize, + newsize, fnrows, fncols, *E, eloc ; + + /* ---------------------------------------------------------------------- */ + /* get parameters */ + /* ---------------------------------------------------------------------- */ + +#ifndef NDEBUG + if (do_what != -1) UMF_debug++ ; + DEBUG0 (("\n\n====================GROW FRONT: do_what: "ID"\n", do_what)) ; + if (do_what != -1) UMF_debug-- ; + ASSERT (Work->do_grow) ; + ASSERT (Work->fnpiv == 0) ; +#endif + + Fcols = Work->Fcols ; + Fcpos = Work->Fcpos ; + E = Work->E ; + + /* ---------------------------------------------------------------------- */ + /* The current front is too small, find the new size */ + /* ---------------------------------------------------------------------- */ + + /* maximum size of frontal matrix for this chain */ + nb = Work->nb ; + fnrows_max = Work->fnrows_max + nb ; + fncols_max = Work->fncols_max + nb ; + ASSERT (fnrows_max >= 0 && (fnrows_max % 2) == 1) ; + DEBUG0 (("Max size: "ID"-by-"ID" (incl. "ID" pivot block\n", + fnrows_max, fncols_max, nb)) ; + + /* current dimensions of frontal matrix: fnr-by-fnc */ + DEBUG0 (("Current : "ID"-by-"ID" (excl "ID" pivot blocks)\n", + Work->fnr_curr, Work->fnc_curr, nb)) ; + ASSERT (Work->fnr_curr >= 0) ; + ASSERT ((Work->fnr_curr % 2 == 1) || Work->fnr_curr == 0) ; + + /* required dimensions of frontal matrix: fnr_min-by-fnc_min */ + fnrows_new = Work->fnrows_new + 1 ; + fncols_new = Work->fncols_new + 1 ; + ASSERT (fnrows_new >= 0) ; + if (fnrows_new % 2 == 0) fnrows_new++ ; + fnrows_new += nb ; + fncols_new += nb ; + fnr_min = MIN (fnrows_new, fnrows_max) ; + fnc_min = MIN (fncols_new, fncols_max) ; + minsize = fnr_min * fnc_min ; + if (INT_OVERFLOW ((double) fnr_min * (double) fnc_min * sizeof (Entry))) + { + /* :: the minimum front size is bigger than the integer maximum :: */ + return (FALSE) ; + } + ASSERT (fnr_min >= 0) ; + ASSERT (fnr_min % 2 == 1) ; + + DEBUG0 (("Min : "ID"-by-"ID"\n", fnr_min, fnc_min)) ; + + /* grow the front to fnr2-by-fnc2, but no bigger than the maximum, + * and no smaller than the minumum. */ + DEBUG0 (("Desired : ("ID"+"ID")-by-("ID"+"ID")\n", fnr2, nb, fnc2, nb)) ; + fnr2 += nb ; + fnc2 += nb ; + ASSERT (fnr2 >= 0) ; + if (fnr2 % 2 == 0) fnr2++ ; + fnr2 = MAX (fnr2, fnr_min) ; + fnc2 = MAX (fnc2, fnc_min) ; + fnr2 = MIN (fnr2, fnrows_max) ; + fnc2 = MIN (fnc2, fncols_max) ; + DEBUG0 (("Try : "ID"-by-"ID"\n", fnr2, fnc2)) ; + ASSERT (fnr2 >= 0) ; + ASSERT (fnr2 % 2 == 1) ; + + s = ((double) fnr2) * ((double) fnc2) ; + if (INT_OVERFLOW (s * sizeof (Entry))) + { + /* :: frontal matrix size int overflow :: */ + /* the desired front size is bigger than the integer maximum */ + /* compute a such that a*a*s < Int_MAX / sizeof (Entry) */ + double a = 0.9 * sqrt ((Int_MAX / sizeof (Entry)) / s) ; + fnr2 = MAX (fnr_min, a * fnr2) ; + fnc2 = MAX (fnc_min, a * fnc2) ; + /* the new frontal size is a*r*a*c = a*a*s */ + newsize = fnr2 * fnc2 ; + ASSERT (fnr2 >= 0) ; + if (fnr2 % 2 == 0) fnr2++ ; + fnc2 = newsize / fnr2 ; + } + + fnr2 = MAX (fnr2, fnr_min) ; + fnc2 = MAX (fnc2, fnc_min) ; + newsize = fnr2 * fnc2 ; + + ASSERT (fnr2 >= 0) ; + ASSERT (fnr2 % 2 == 1) ; + ASSERT (fnr2 >= fnr_min) ; + ASSERT (fnc2 >= fnc_min) ; + ASSERT (newsize >= minsize) ; + + /* ---------------------------------------------------------------------- */ + /* free the current front if it is empty of any numerical values */ + /* ---------------------------------------------------------------------- */ + + if (E [0] && do_what != 1) + { + /* free the current front, if it exists and has nothing in it */ + DEBUG0 (("Freeing empty front\n")) ; + UMF_mem_free_tail_block (Numeric, E [0]) ; + E [0] = 0 ; + Work->Flublock = (Entry *) NULL ; + Work->Flblock = (Entry *) NULL ; + Work->Fublock = (Entry *) NULL ; + Work->Fcblock = (Entry *) NULL ; + } + + /* ---------------------------------------------------------------------- */ + /* allocate the new front, doing garbage collection if necessary */ + /* ---------------------------------------------------------------------- */ + +#ifndef NDEBUG + UMF_allocfail = FALSE ; + if (UMF_gprob > 0) /* a double relop, but ignore NaN case */ + { + double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; + DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ; + UMF_allocfail = rrr < UMF_gprob ; + if (UMF_allocfail) DEBUGm2 (("Random garbage collection (grow)\n")) ; + } +#endif + + DEBUG0 (("Attempt size: "ID"-by-"ID"\n", fnr2, fnc2)) ; + eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; + + if (!eloc) + { + /* Do garbage collection, realloc, and try again. Compact the current + * contribution block in the front to fnrows-by-fncols. Note that + * there are no pivot rows/columns in current front. Do not recompute + * Fcpos in UMF_garbage_collection. */ + DEBUGm3 (("get_memory from umf_grow_front\n")) ; + if (!UMF_get_memory (Numeric, Work, 1 + UNITS (Entry, newsize), + Work->fnrows, Work->fncols, FALSE)) + { + /* :: out of memory in umf_grow_front :: */ + return (FALSE) ; /* out of memory */ + } + DEBUG0 (("Attempt size: "ID"-by-"ID" again\n", fnr2, fnc2)) ; + eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; + } + + /* try again with something smaller */ + while ((fnr2 != fnr_min || fnc2 != fnc_min) && !eloc) + { + fnr2 = MIN (fnr2 - 2, fnr2 * UMF_REALLOC_REDUCTION) ; + fnc2 = MIN (fnc2 - 2, fnc2 * UMF_REALLOC_REDUCTION) ; + ASSERT (fnr_min >= 0) ; + ASSERT (fnr_min % 2 == 1) ; + fnr2 = MAX (fnr_min, fnr2) ; + fnc2 = MAX (fnc_min, fnc2) ; + ASSERT (fnr2 >= 0) ; + if (fnr2 % 2 == 0) fnr2++ ; + newsize = fnr2 * fnc2 ; + DEBUGm3 (("Attempt smaller size: "ID"-by-"ID" minsize "ID"-by-"ID"\n", + fnr2, fnc2, fnr_min, fnc_min)) ; + eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; + } + + /* try again with the smallest possible size */ + if (!eloc) + { + fnr2 = fnr_min ; + fnc2 = fnc_min ; + newsize = minsize ; + DEBUG0 (("Attempt minsize: "ID"-by-"ID"\n", fnr2, fnc2)) ; + eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; + } + + if (!eloc) + { + /* out of memory */ + return (FALSE) ; + } + + ASSERT (fnr2 >= 0) ; + ASSERT (fnr2 % 2 == 1) ; + ASSERT (fnr2 >= fnr_min && fnc2 >= fnc_min) ; + + /* ---------------------------------------------------------------------- */ + /* copy the old frontal matrix into the new one */ + /* ---------------------------------------------------------------------- */ + + /* old contribution block (if any) */ + fnr_curr = Work->fnr_curr ; /* garbage collection can change fn*_curr */ + ASSERT (fnr_curr >= 0) ; + ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ; + fnrows = Work->fnrows ; + fncols = Work->fncols ; + Fcold = Work->Fcblock ; + + /* remove nb from the sizes */ + fnr2 -= nb ; + fnc2 -= nb ; + + /* new frontal matrix */ + Work->Flublock = (Entry *) (Numeric->Memory + eloc) ; + Work->Flblock = Work->Flublock + nb * nb ; + Work->Fublock = Work->Flblock + nb * fnr2 ; + Work->Fcblock = Work->Fublock + nb * fnc2 ; + Fcnew = Work->Fcblock ; + + if (E [0]) + { + /* copy the old contribution block into the new one */ + for (j = 0 ; j < fncols ; j++) + { + col = Fcols [j] ; + DEBUG1 (("copy col "ID" \n",col)) ; + ASSERT (col >= 0 && col < Work->n_col) ; + for (i = 0 ; i < fnrows ; i++) + { + Fcnew [i] = Fcold [i] ; + } + Fcnew += fnr2 ; + Fcold += fnr_curr ; + DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ; + Fcpos [col] = j * fnr2 ; + } + } + else if (do_what == 2) + { + /* just find the new column offsets */ + for (j = 0 ; j < fncols ; j++) + { + col = Fcols [j] ; + DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ; + Fcpos [col] = j * fnr2 ; + } + } + + /* free the old frontal matrix */ + UMF_mem_free_tail_block (Numeric, E [0]) ; + + /* ---------------------------------------------------------------------- */ + /* new frontal matrix size */ + /* ---------------------------------------------------------------------- */ + + E [0] = eloc ; + Work->fnr_curr = fnr2 ; /* C block is fnr2-by-fnc2 */ + Work->fnc_curr = fnc2 ; + Work->fcurr_size = newsize ; /* including LU, L, U, and C blocks */ + Work->do_grow = FALSE ; /* the front has just been grown */ + + ASSERT (Work->fnr_curr >= 0) ; + ASSERT (Work->fnr_curr % 2 == 1) ; + DEBUG0 (("Newly grown front: "ID"+"ID" by "ID"+"ID"\n", Work->fnr_curr, + nb, Work->fnc_curr, nb)) ; + return (TRUE) ; +}