Mercurial > octave-nkf
diff liboctave/UMFPACK/UMFPACK/Source/umf_create_element.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_create_element.c Fri Feb 25 19:55:28 2005 +0000 @@ -0,0 +1,604 @@ +/* ========================================================================== */ +/* === UMF_create_element =================================================== */ +/* ========================================================================== */ + +/* -------------------------------------------------------------------------- */ +/* 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 */ +/* -------------------------------------------------------------------------- */ + +/* + Factorization of a frontal matrix is complete. Create a new element for + later assembly into a subsequent frontal matrix. Returns TRUE if + successful, FALSE if out of memory. +*/ + +#include "umf_internal.h" +#include "umf_mem_alloc_element.h" +#include "umf_mem_alloc_tail_block.h" +#include "umf_mem_free_tail_block.h" +#include "umf_get_memory.h" + +/* ========================================================================== */ +/* === copy_column ========================================================== */ +/* ========================================================================== */ + +PRIVATE void copy_column (Int len, Entry *X, Entry *Y) +{ + Int i ; +#pragma ivdep + for (i = 0 ; i < len ; i++) + { + Y [i] = X [i] ; + } +} + +/* ========================================================================== */ +/* === UMF_create_element =================================================== */ +/* ========================================================================== */ + +GLOBAL Int UMF_create_element +( + NumericType *Numeric, + WorkType *Work, + SymbolicType *Symbolic +) +{ + /* ---------------------------------------------------------------------- */ + /* local variables */ + /* ---------------------------------------------------------------------- */ + + Int j, col, row, *Fcols, *Frows, fnrows, fncols, *Cols, len, needunits, t1, + t2, size, e, i, *E, *Fcpos, *Frpos, *Rows, eloc, fnr_curr, f, + got_memory, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, max_mark, + *Col_degree, *Col_tlen, nn, n_row, n_col, r2, c2, do_Fcpos ; + Entry *C, *Fcol ; + Element *ep ; + Unit *p, *Memory ; + Tuple *tp, *tp1, *tp2, tuple, *tpend ; +#ifndef NDEBUG + DEBUG2 (("FRONTAL WRAPUP\n")) ; + UMF_dump_current_front (Numeric, Work, TRUE) ; +#endif + + /* ---------------------------------------------------------------------- */ + /* get parameters */ + /* ---------------------------------------------------------------------- */ + + ASSERT (Work->fnpiv == 0) ; + ASSERT (Work->fnzeros == 0) ; + Row_degree = Numeric->Rperm ; + Row_tuples = Numeric->Uip ; + Row_tlen = Numeric->Uilen ; + Col_degree = Numeric->Cperm ; + Col_tuples = Numeric->Lip ; + Col_tlen = Numeric->Lilen ; + n_row = Work->n_row ; + n_col = Work->n_col ; + nn = MAX (n_row, n_col) ; + Fcols = Work->Fcols ; + Frows = Work->Frows ; + Fcpos = Work->Fcpos ; + Frpos = Work->Frpos ; + Memory = Numeric->Memory ; + fncols = Work->fncols ; + fnrows = Work->fnrows ; + + tp = (Tuple *) NULL ; + tp1 = (Tuple *) NULL ; + tp2 = (Tuple *) NULL ; + + /* ---------------------------------------------------------------------- */ + /* add the current frontal matrix to the degrees of each column */ + /* ---------------------------------------------------------------------- */ + + if (!Symbolic->fixQ) + { + /* but only if the column ordering is not fixed */ +#pragma ivdep + for (j = 0 ; j < fncols ; j++) + { + /* add the current frontal matrix to the degree */ + ASSERT (Fcols [j] >= 0 && Fcols [j] < n_col) ; + Col_degree [Fcols [j]] += fnrows ; + } + } + + /* ---------------------------------------------------------------------- */ + /* add the current frontal matrix to the degrees of each row */ + /* ---------------------------------------------------------------------- */ + +#pragma ivdep + for (i = 0 ; i < fnrows ; i++) + { + /* add the current frontal matrix to the degree */ + ASSERT (Frows [i] >= 0 && Frows [i] < n_row) ; + Row_degree [Frows [i]] += fncols ; + } + + /* ---------------------------------------------------------------------- */ + /* Reset the external degree counters */ + /* ---------------------------------------------------------------------- */ + + E = Work->E ; + max_mark = MAX_MARK (nn) ; + + if (!Work->pivcol_in_front) + { + /* clear the external column degrees. no more Usons of current front */ + Work->cdeg0 += (nn + 1) ; + if (Work->cdeg0 >= max_mark) + { + /* guard against integer overflow. This is very rare */ + DEBUG1 (("Integer overflow, cdeg\n")) ; + Work->cdeg0 = 1 ; +#pragma ivdep + for (e = 1 ; e <= Work->nel ; e++) + { + if (E [e]) + { + ep = (Element *) (Memory + E [e]) ; + ep->cdeg = 0 ; + } + } + } + } + + if (!Work->pivrow_in_front) + { + /* clear the external row degrees. no more Lsons of current front */ + Work->rdeg0 += (nn + 1) ; + if (Work->rdeg0 >= max_mark) + { + /* guard against integer overflow. This is very rare */ + DEBUG1 (("Integer overflow, rdeg\n")) ; + Work->rdeg0 = 1 ; +#pragma ivdep + for (e = 1 ; e <= Work->nel ; e++) + { + if (E [e]) + { + ep = (Element *) (Memory + E [e]) ; + ep->rdeg = 0 ; + } + } + } + } + + /* ---------------------------------------------------------------------- */ + /* clear row/col offsets */ + /* ---------------------------------------------------------------------- */ + + if (!Work->pivrow_in_front) + { +#pragma ivdep + for (j = 0 ; j < fncols ; j++) + { + Fcpos [Fcols [j]] = EMPTY ; + } + } + + if (!Work->pivcol_in_front) + { +#pragma ivdep + for (i = 0 ; i < fnrows ; i++) + { + Frpos [Frows [i]] = EMPTY ; + } + } + + if (fncols <= 0 || fnrows <= 0) + { + /* no element to create */ + DEBUG2 (("Element evaporation\n")) ; + Work->prior_element = EMPTY ; + return (TRUE) ; + } + + /* ---------------------------------------------------------------------- */ + /* create element for later assembly */ + /* ---------------------------------------------------------------------- */ + +#ifndef NDEBUG + UMF_allocfail = FALSE ; + if (UMF_gprob > 0) + { + double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; + DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ; + UMF_allocfail = rrr < UMF_gprob ; + if (UMF_allocfail) DEBUGm2 (("Random garbage collection (create)\n")); + } +#endif + + needunits = 0 ; + got_memory = FALSE ; + eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C, + &needunits, &ep) ; + + /* if UMF_get_memory needs to be called */ + if (Work->do_grow) + { + /* full compaction of current frontal matrix, since UMF_grow_front will + * be called next anyway. */ + r2 = fnrows ; + c2 = fncols ; + do_Fcpos = FALSE ; + } + else + { + /* partial compaction. */ + r2 = MAX (fnrows, Work->fnrows_new + 1) ; + c2 = MAX (fncols, Work->fncols_new + 1) ; + /* recompute Fcpos if pivot row is in the front */ + do_Fcpos = Work->pivrow_in_front ; + } + + if (!eloc) + { + /* Do garbage collection, realloc, and try again. */ + /* Compact the current front if it needs to grow anyway. */ + /* Note that there are no pivot rows or columns in the current front */ + DEBUGm3 (("get_memory from umf_create_element, 1\n")) ; + if (!UMF_get_memory (Numeric, Work, needunits, r2, c2, do_Fcpos)) + { + /* :: out of memory in umf_create_element (1) :: */ + DEBUGm4 (("out of memory: create element (1)\n")) ; + return (FALSE) ; /* out of memory */ + } + got_memory = TRUE ; + Memory = Numeric->Memory ; + eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C, + &needunits, &ep) ; + ASSERT (eloc >= 0) ; + if (!eloc) + { + /* :: out of memory in umf_create_element (2) :: */ + DEBUGm4 (("out of memory: create element (2)\n")) ; + return (FALSE) ; /* out of memory */ + } + } + + e = ++(Work->nel) ; /* get the name of this new frontal matrix */ + Work->prior_element = e ; + DEBUG8 (("wrapup e "ID" nel "ID"\n", e, Work->nel)) ; + + ASSERT (e > 0 && e < Work->elen) ; + ASSERT (E [e] == 0) ; + E [e] = eloc ; + + if (Work->pivcol_in_front) + { + /* the new element is a Uson of the next frontal matrix */ + ep->cdeg = Work->cdeg0 ; + } + + if (Work->pivrow_in_front) + { + /* the new element is an Lson of the next frontal matrix */ + ep->rdeg = Work->rdeg0 ; + } + + /* ---------------------------------------------------------------------- */ + /* copy frontal matrix into the new element */ + /* ---------------------------------------------------------------------- */ + +#pragma ivdep + for (i = 0 ; i < fnrows ; i++) + { + Rows [i] = Frows [i] ; + } +#pragma ivdep + for (i = 0 ; i < fncols ; i++) + { + Cols [i] = Fcols [i] ; + } + Fcol = Work->Fcblock ; + DEBUG0 (("copy front "ID" by "ID"\n", fnrows, fncols)) ; + fnr_curr = Work->fnr_curr ; + ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ; + for (j = 0 ; j < fncols ; j++) + { + copy_column (fnrows, Fcol, C) ; +#if 0 +#ifdef USE_NO_BLAS + copy_column (fnrows, Fcol, C) ; +#else + could also use BLAS-COPY (fnrows, Fcol, C) here, but it is typically + not as fast as the inlined copy_column subroutine, above. +#endif + for (i = 0 ; i < fnrows ; i++) + { + C [i] = Fcol [i] ; + } +#endif + Fcol += fnr_curr ; + C += fnrows ; + } + + DEBUG8 (("element copied\n")) ; + + /* ---------------------------------------------------------------------- */ + /* add tuples for the new element */ + /* ---------------------------------------------------------------------- */ + + tuple.e = e ; + + if (got_memory) + { + + /* ------------------------------------------------------------------ */ + /* UMF_get_memory ensures enough space exists for each new tuple */ + /* ------------------------------------------------------------------ */ + + /* place (e,f) in the element list of each column */ + for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++) + { + col = Fcols [tuple.f] ; + ASSERT (col >= 0 && col < n_col) ; + ASSERT (NON_PIVOTAL_COL (col)) ; + ASSERT (Col_tuples [col]) ; + tp = ((Tuple *) (Memory + Col_tuples [col])) + Col_tlen [col]++ ; + *tp = tuple ; + } + + /* ------------------------------------------------------------------ */ + + /* place (e,f) in the element list of each row */ + for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++) + { + row = Frows [tuple.f] ; + ASSERT (row >= 0 && row < n_row) ; + ASSERT (NON_PIVOTAL_ROW (row)) ; + ASSERT (Row_tuples [row]) ; + tp = ((Tuple *) (Memory + Row_tuples [row])) + Row_tlen [row]++ ; + *tp = tuple ; + } + + } + else + { + + /* ------------------------------------------------------------------ */ + /* place (e,f) in the element list of each column */ + /* ------------------------------------------------------------------ */ + + /* might not have enough space for each tuple */ + + for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++) + { + col = Fcols [tuple.f] ; + ASSERT (col >= 0 && col < n_col) ; + ASSERT (NON_PIVOTAL_COL (col)) ; + t1 = Col_tuples [col] ; + DEBUG1 (("Placing on col:"ID" , tuples at "ID"\n", + col, Col_tuples [col])) ; + + size = 0 ; + len = 0 ; + + if (t1) + { + p = Memory + t1 ; + tp = (Tuple *) p ; + size = GET_BLOCK_SIZE (p) ; + len = Col_tlen [col] ; + tp2 = tp + len ; + } + + needunits = UNITS (Tuple, len + 1) ; + DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n", + len, size, needunits)); + + if (needunits > size && t1) + { + /* prune the tuples */ + tp1 = tp ; + tp2 = tp ; + tpend = tp + len ; + for ( ; tp < tpend ; tp++) + { + e = tp->e ; + ASSERT (e > 0 && e <= Work->nel) ; + if (!E [e]) continue ; /* element already deallocated */ + f = tp->f ; + p = Memory + E [e] ; + ep = (Element *) p ; + p += UNITS (Element, 1) ; + Cols = (Int *) p ; + ; + if (Cols [f] == EMPTY) continue ; /* already assembled */ + ASSERT (col == Cols [f]) ; + *tp2++ = *tp ; /* leave the tuple in the list */ + } + len = tp2 - tp1 ; + Col_tlen [col] = len ; + needunits = UNITS (Tuple, len + 1) ; + } + + if (needunits > size) + { + /* no room exists - reallocate elsewhere */ + DEBUG1 (("REALLOCATE Col: "ID", size "ID" to "ID"\n", + col, size, 2*needunits)) ; + +#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 gar. (col tuple)\n")) ; + } +#endif + + needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ; + t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ; + if (!t2) + { + /* :: get memory in umf_create_element (1) :: */ + /* get memory, reconstruct all tuple lists, and return */ + /* Compact the current front if it needs to grow anyway. */ + /* Note: no pivot rows or columns in the current front */ + DEBUGm4 (("get_memory from umf_create_element, 1\n")) ; + return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos)); + } + Col_tuples [col] = t2 ; + tp2 = (Tuple *) (Memory + t2) ; + if (t1) + { + for (i = 0 ; i < len ; i++) + { + *tp2++ = *tp1++ ; + } + UMF_mem_free_tail_block (Numeric, t1) ; + } + } + + /* place the new (e,f) tuple in the element list of the column */ + Col_tlen [col]++ ; + *tp2 = tuple ; + } + + /* ------------------------------------------------------------------ */ + /* place (e,f) in the element list of each row */ + /* ------------------------------------------------------------------ */ + + for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++) + { + row = Frows [tuple.f] ; + ASSERT (row >= 0 && row < n_row) ; + ASSERT (NON_PIVOTAL_ROW (row)) ; + t1 = Row_tuples [row] ; + DEBUG1 (("Placing on row:"ID" , tuples at "ID"\n", + row, Row_tuples [row])) ; + + size = 0 ; + len = 0 ; + if (t1) + { + p = Memory + t1 ; + tp = (Tuple *) p ; + size = GET_BLOCK_SIZE (p) ; + len = Row_tlen [row] ; + tp2 = tp + len ; + } + + needunits = UNITS (Tuple, len + 1) ; + DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n", + len, size, needunits)) ; + + if (needunits > size && t1) + { + /* prune the tuples */ + tp1 = tp ; + tp2 = tp ; + tpend = tp + len ; + for ( ; tp < tpend ; tp++) + { + e = tp->e ; + ASSERT (e > 0 && e <= Work->nel) ; + if (!E [e]) + { + continue ; /* element already deallocated */ + } + f = tp->f ; + p = Memory + E [e] ; + ep = (Element *) p ; + p += UNITS (Element, 1) ; + Cols = (Int *) p ; + Rows = Cols + (ep->ncols) ; + if (Rows [f] == EMPTY) continue ; /* already assembled */ + ASSERT (row == Rows [f]) ; + *tp2++ = *tp ; /* leave the tuple in the list */ + } + len = tp2 - tp1 ; + Row_tlen [row] = len ; + needunits = UNITS (Tuple, len + 1) ; + } + + if (needunits > size) + { + /* no room exists - reallocate elsewhere */ + DEBUG1 (("REALLOCATE Row: "ID", size "ID" to "ID"\n", + row, size, 2*needunits)) ; + +#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 gar. (row tuple)\n")) ; + } +#endif + + needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ; + t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ; + if (!t2) + { + /* :: get memory in umf_create_element (2) :: */ + /* get memory, reconstruct all tuple lists, and return */ + /* Compact the current front if it needs to grow anyway. */ + /* Note: no pivot rows or columns in the current front */ + DEBUGm4 (("get_memory from umf_create_element, 2\n")) ; + return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos)); + } + Row_tuples [row] = t2 ; + tp2 = (Tuple *) (Memory + t2) ; + if (t1) + { + for (i = 0 ; i < len ; i++) + { + *tp2++ = *tp1++ ; + } + UMF_mem_free_tail_block (Numeric, t1) ; + } + } + + /* place the new (e,f) tuple in the element list of the row */ + Row_tlen [row]++ ; + *tp2 = tuple ; + } + + } + + /* ---------------------------------------------------------------------- */ + +#ifndef NDEBUG + DEBUG1 (("Done extending\nFINAL: element row pattern: len="ID"\n", fncols)); + for (j = 0 ; j < fncols ; j++) DEBUG1 ((""ID"\n", Fcols [j])) ; + DEBUG1 (("FINAL: element col pattern: len="ID"\n", fnrows)) ; + for (j = 0 ; j < fnrows ; j++) DEBUG1 ((""ID"\n", Frows [j])) ; + for (j = 0 ; j < fncols ; j++) + { + col = Fcols [j] ; + ASSERT (col >= 0 && col < n_col) ; + UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ; + } + for (j = 0 ; j < fnrows ; j++) + { + row = Frows [j] ; + ASSERT (row >= 0 && row < n_row) ; + UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ; + } + if (n_row < 1000 && n_col < 1000) + { + UMF_dump_memory (Numeric) ; + } + DEBUG1 (("New element, after filling with stuff: "ID"\n", e)) ; + UMF_dump_element (Numeric, Work, e, TRUE) ; + if (nn < 1000) + { + DEBUG4 (("Matrix dump, after New element: "ID"\n", e)) ; + UMF_dump_matrix (Numeric, Work, TRUE) ; + } + DEBUG3 (("FRONTAL WRAPUP DONE\n")) ; +#endif + + return (TRUE) ; +}