aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjthorn <jthorn@f88db872-0e4f-0410-b76b-b9085cfa78c5>2003-06-04 11:49:29 +0000
committerjthorn <jthorn@f88db872-0e4f-0410-b76b-b9085cfa78c5>2003-06-04 11:49:29 +0000
commit2e72b0e19eb45f00fb6fc7411d1bb9e3be0b3d8f (patch)
treef93e703ce65b39a221db4864731321067396846e
parentc37b4c96f3426ed7019be2dd9acd416853c16cf2 (diff)
import the rest (of that subset that I need) of UMFPACK into CVS
the make.code.* and wrap* routines are mine, everything else here is from UMFPACK v4.0 git-svn-id: http://svn.einsteintoolkit.org/cactus/EinsteinAnalysis/AHFinderDirect/trunk@1092 f88db872-0e4f-0410-b76b-b9085cfa78c5
-rw-r--r--src/sparse-matrix/umfpack/README6
-rw-r--r--src/sparse-matrix/umfpack/make.code.defn87
-rw-r--r--src/sparse-matrix/umfpack/make.code.deps8
-rw-r--r--src/sparse-matrix/umfpack/umf_analyze.c883
-rw-r--r--src/sparse-matrix/umfpack/umf_apply_order.c42
-rw-r--r--src/sparse-matrix/umfpack/umf_assemble.c1037
-rw-r--r--src/sparse-matrix/umfpack/umf_blas3_update.c125
-rw-r--r--src/sparse-matrix/umfpack/umf_build_tuples.c158
-rw-r--r--src/sparse-matrix/umfpack/umf_build_tuples_usage.c75
-rw-r--r--src/sparse-matrix/umfpack/umf_colamd.c3077
-rw-r--r--src/sparse-matrix/umfpack/umf_create_element.c534
-rw-r--r--src/sparse-matrix/umfpack/umf_dump.c1163
-rw-r--r--src/sparse-matrix/umfpack/umf_extend_front.c673
-rw-r--r--src/sparse-matrix/umfpack/umf_free.c45
-rw-r--r--src/sparse-matrix/umfpack/umf_garbage_collection.c403
-rw-r--r--src/sparse-matrix/umfpack/umf_get_memory.c210
-rw-r--r--src/sparse-matrix/umfpack/umf_init_front.c201
-rw-r--r--src/sparse-matrix/umfpack/umf_is_permutation.c54
-rw-r--r--src/sparse-matrix/umfpack/umf_kernel.c251
-rw-r--r--src/sparse-matrix/umfpack/umf_kernel_init.c301
-rw-r--r--src/sparse-matrix/umfpack/umf_kernel_init_usage.c54
-rw-r--r--src/sparse-matrix/umfpack/umf_kernel_wrapup.c356
-rw-r--r--src/sparse-matrix/umfpack/umf_local_search.c1487
-rw-r--r--src/sparse-matrix/umfpack/umf_lsolve.c120
-rw-r--r--src/sparse-matrix/umfpack/umf_ltsolve.c187
-rw-r--r--src/sparse-matrix/umfpack/umf_malloc.c81
-rw-r--r--src/sparse-matrix/umfpack/umf_mem_alloc_element.c98
-rw-r--r--src/sparse-matrix/umfpack/umf_mem_alloc_head_block.c46
-rw-r--r--src/sparse-matrix/umfpack/umf_mem_alloc_tail_block.c133
-rw-r--r--src/sparse-matrix/umfpack/umf_mem_free_tail_block.c149
-rw-r--r--src/sparse-matrix/umfpack/umf_mem_init_memoryspace.c65
-rw-r--r--src/sparse-matrix/umfpack/umf_order_front_tree.c100
-rw-r--r--src/sparse-matrix/umfpack/umf_realloc.c56
-rw-r--r--src/sparse-matrix/umfpack/umf_row_search.c626
-rw-r--r--src/sparse-matrix/umfpack/umf_scale_column.c773
-rw-r--r--src/sparse-matrix/umfpack/umf_set_stats.c109
-rw-r--r--src/sparse-matrix/umfpack/umf_solve.c1024
-rw-r--r--src/sparse-matrix/umfpack/umf_symbolic_usage.c33
-rw-r--r--src/sparse-matrix/umfpack/umf_transpose.c385
-rw-r--r--src/sparse-matrix/umfpack/umf_tuple_lengths.c104
-rw-r--r--src/sparse-matrix/umfpack/umf_usolve.c167
-rw-r--r--src/sparse-matrix/umfpack/umf_utsolve.c255
-rw-r--r--src/sparse-matrix/umfpack/umf_valid_numeric.c48
-rw-r--r--src/sparse-matrix/umfpack/umf_valid_symbolic.c49
-rw-r--r--src/sparse-matrix/umfpack/umfpack_defaults.c111
-rw-r--r--src/sparse-matrix/umfpack/umfpack_free_numeric.c51
-rw-r--r--src/sparse-matrix/umfpack/umfpack_free_symbolic.c50
-rw-r--r--src/sparse-matrix/umfpack/umfpack_get_lunz.c57
-rw-r--r--src/sparse-matrix/umfpack/umfpack_get_numeric.c816
-rw-r--r--src/sparse-matrix/umfpack/umfpack_get_symbolic.c172
-rw-r--r--src/sparse-matrix/umfpack/umfpack_numeric.c736
-rw-r--r--src/sparse-matrix/umfpack/umfpack_qsymbolic.c1347
-rw-r--r--src/sparse-matrix/umfpack/umfpack_solve.c258
-rw-r--r--src/sparse-matrix/umfpack/umfpack_symbolic.c34
-rw-r--r--src/sparse-matrix/umfpack/umfpack_timer.c70
-rw-r--r--src/sparse-matrix/umfpack/umfpack_transpose.c113
-rw-r--r--src/sparse-matrix/umfpack/wrap_umf_ltsolve.c2
-rw-r--r--src/sparse-matrix/umfpack/wrap_umf_utsolve.c2
-rw-r--r--src/sparse-matrix/umfpack/wrap_umfpack_wsolve.c2
59 files changed, 19658 insertions, 1 deletions
diff --git a/src/sparse-matrix/umfpack/README b/src/sparse-matrix/umfpack/README
index b19cca2..776817e 100644
--- a/src/sparse-matrix/umfpack/README
+++ b/src/sparse-matrix/umfpack/README
@@ -1,9 +1,13 @@
This directory contains a subset of the files from the
UMFPACK Version 4.0 (Apr 11, 2002) sparse matrix package.
UMFPACK is copyright (c) 2002 by Timothy A. Davis.
+
See License for the UMFPACK license.
See README.UMFPACK for the original UMFPACK README file, including
the url where the full package (including documentation) may be optained.
-make.code.defn controls compilation of this directory in Cactus.
+make.code.defn controls the Cactus compilation of this directory.
+
+umfpack_wsolve.c is a copy of umfpack_solve.c to work around
+limitations in the Cactus make.code.defn system.
diff --git a/src/sparse-matrix/umfpack/make.code.defn b/src/sparse-matrix/umfpack/make.code.defn
new file mode 100644
index 0000000..4913278
--- /dev/null
+++ b/src/sparse-matrix/umfpack/make.code.defn
@@ -0,0 +1,87 @@
+# Cactus specification of things to be compiled in this directory
+# $Header$
+
+#
+# UMFPACK comes with a Makefile which compiles many of the source files
+# multiple times with different -D compiler options, both to generate the
+# 4 UMFPACK variants (real/complex, int/long), and for other purposes.
+# Alas, Cactus doesn't seem to provide any way to use a Makefile for
+# this subdirectory, and still use make.code.defn building for the
+# rest of this thorn. :( :(
+#
+# Instead, we [have to] fake things with this make.code.defn and the
+# accompanying make.code.deps . Fortunately, we only need one UMFPACK
+# variant: We know it's real, but we actually want the integer datatype
+# to match Fortran's (since ../../elliptic/row_sparse_matrix.{cc,hh}
+# potentially use the same data structures for both UMFPACK and ILUCG
+# matrices, and ILUCG is Fortran). This ought to be determined by a
+# configure script, but for now (FIXME) we just hard-wire it to long
+# with -D compile flags set in make.code.deps .
+#
+# For the other multiple-compilation and special-compilation-flags cases,
+# we use wrapper files which #define the appropriate symbols, then #include
+# the main UMFPACK source files.
+#
+
+# Source files in this directory
+SRCS = \
+ umf_analyze.c \
+ umf_apply_order.c \
+ umf_assemble.c \
+ umf_blas3_update.c \
+ umf_build_tuples.c \
+ umf_build_tuples_usage.c \
+ umf_colamd.c \
+ umf_create_element.c \
+ umf_dump.c \
+ umf_extend_front.c \
+ umf_free.c \
+ umf_garbage_collection.c \
+ umf_get_memory.c \
+ umf_init_front.c \
+ umf_is_permutation.c \
+ umf_kernel.c \
+ umf_kernel_init.c \
+ umf_kernel_init_usage.c \
+ umf_kernel_wrapup.c \
+ umf_local_search.c \
+ umf_lsolve.c \
+ umf_ltsolve.c \
+ umf_malloc.c \
+ umf_mem_alloc_element.c \
+ umf_mem_alloc_head_block.c \
+ umf_mem_alloc_tail_block.c \
+ umf_mem_free_tail_block.c \
+ umf_mem_init_memoryspace.c \
+ umf_order_front_tree.c \
+ umf_realloc.c \
+ umf_row_search.c \
+ umf_scale_column.c \
+ umf_set_stats.c \
+ umf_solve.c \
+ umf_symbolic_usage.c \
+ umf_transpose.c \
+ umf_tuple_lengths.c \
+ umf_usolve.c \
+ umf_utsolve.c \
+ umf_valid_numeric.c \
+ umf_valid_symbolic.c \
+ umfpack_defaults.c \
+ umfpack_free_numeric.c \
+ umfpack_free_symbolic.c \
+ umfpack_get_lunz.c \
+ umfpack_get_numeric.c \
+ umfpack_get_symbolic.c \
+ umfpack_numeric.c \
+ umfpack_qsymbolic.c \
+ umfpack_solve.c \
+ umfpack_symbolic.c \
+ umfpack_timer.c \
+ umfpack_transpose.c \
+ \
+ wrap_umf_ltsolve.c \
+ wrap_umf_utsolve.c \
+ wrap_umfpack_wsolve.c
+
+# Subdirectories containing source files
+SUBDIRS =
diff --git a/src/sparse-matrix/umfpack/make.code.deps b/src/sparse-matrix/umfpack/make.code.deps
new file mode 100644
index 0000000..e0bea85
--- /dev/null
+++ b/src/sparse-matrix/umfpack/make.code.deps
@@ -0,0 +1,8 @@
+# extra Make rules for Cactus compilation of things in this directory
+# $Header$
+
+#
+# See the header comments in make.code.defn for general comments.
+#
+CFLAGS += -DNBLAS -DNDEBUG -DLONG
+CPPFLAGS += -DNBLAS -DNDEBUG -DDLONG
diff --git a/src/sparse-matrix/umfpack/umf_analyze.c b/src/sparse-matrix/umfpack/umf_analyze.c
new file mode 100644
index 0000000..0490ece
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_analyze.c
@@ -0,0 +1,883 @@
+/* ========================================================================== */
+/* === UMF_analyze ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Symbolic LL' factorization of A'*A, to get upper bounds on the size of
+ L and U for LU = PAQ, and to determine the frontal matrices and
+ (supernodal) column elimination tree. No fill-reducing column pre-ordering
+ is used.
+
+ Returns TRUE if successful, FALSE if out of memory. UMF_analyze can only
+ run out of memory if anzmax (which is Ap [n_row]) is too small.
+
+ Uses workspace of size O(nonzeros in A). On input, the matrix A is
+ stored in row-form at the tail end of Ai. It is destroyed on output.
+ The rows of A must be sorted by increasing first column index.
+ The matrix is assumed to be valid.
+
+ Empty rows and columns have already been removed.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_order_front_tree.h"
+#include "umf_apply_order.h"
+
+/* ========================================================================== */
+
+GLOBAL Int UMF_analyze
+(
+ Int n_row, /* A is n_row-by-n_col */
+ Int n_col,
+ Int Ai [ ], /* Ai [Ap [0]..Ap[n_row]-1]: column indices */
+ /* destroyed on output. Note that this is NOT the */
+ /* user's Ai that was passed to UMFPACK_*symbolic */
+ /* size of Ai, Ap [n_row] = anzmax >= anz + n_col */
+ /* Ap [0] must be => n_col. The space to the */
+ /* front of Ai is used as workspace. */
+
+ Int Ap [ ], /* of size MAX (n_row, n_col) + 1 */
+ /* Ap [0..n_row]: row pointers */
+ /* Row i is in Ai [Ap [i] ... Ap [i+1]-1] */
+
+ /* rows must have smallest col index first, or be */
+ /* in sorted form. Used as workspace of size n_col */
+ /* and destroyed. */
+
+ /* Note that this is NOT the */
+ /* user's Ap that was passed to UMFPACK_*symbolic */
+
+ Int Up [ ], /* workspace of size n_col, and output column perm. */
+
+ /* temporary workspaces: */
+ Int W [ ], /* W [0..n_col-1] */
+ Int Link [ ], /* Link [0..n_col-1] */
+
+ /* output: information about each frontal matrix: */
+ Int Front_ncols [ ], /* size n_col */
+ Int Front_nrows [ ], /* of size n_col */
+ Int Front_npivcol [ ], /* of size n_col */
+ Int Front_parent [ ], /* of size n_col */
+ Int *nfr_out,
+
+ Int *p_ncompactions /* number of compactions in UMF_analyze */
+)
+{
+ /* ====================================================================== */
+ /* ==== local variables ================================================= */
+ /* ====================================================================== */
+
+ Int j, j3, col, k, row, parent, j2, pdest, p, p2, thickness, npivots, nfr,
+ frsize, i, *Winv, kk, npiv, jnext, krow, knext, pfirst,
+ jlast, ncompactions, *Stack, *Front_maxfr, *Front_order, *Front_child,
+ *Front_sibling, fprev, maxfrsize, bigf, fnext, bigfprev, f, Wflag,
+ npivcol, fallrows, fallcols, fpiv, frows, fcols ;
+
+#ifndef NDEBUG
+ Int nfr2, nchild ;
+#endif
+
+ nfr = 0 ;
+ DEBUG0 (("UMF_analyze: anzmax "ID" anrow "ID" ancol "ID"\n",
+ Ap [n_row], n_row, n_col)) ;
+
+ /* ====================================================================== */
+ /* ==== initializations ================================================= */
+ /* ====================================================================== */
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ Link [j] = EMPTY ;
+ W [j] = EMPTY ;
+ Up [j] = EMPTY ;
+
+ /* Frontal matrix data structure: */
+ Front_npivcol [j] = 0 ; /* number of pivot columns */
+ Front_nrows [j] = 0 ; /* number of rows, incl. pivot rows */
+ Front_ncols [j] = 0 ; /* number of cols, incl. pivot cols */
+ Front_parent [j] = EMPTY ; /* parent front */
+ /* Note that only non-pivotal columns are stored in a front (a "row" */
+ /* of U) during elimination. */
+ }
+
+ /* the rows must be sorted by increasing min col */
+ krow = 0 ;
+ pfirst = Ap [0] ;
+ jlast = EMPTY ;
+ jnext = EMPTY ;
+ Wflag = 0 ;
+
+ ASSERT (pfirst >= n_col) ; /* Ai must be large enough */
+
+ /* pdest points to the first free space in Ai */
+ pdest = 0 ;
+ ncompactions = 0 ;
+
+ /* ====================================================================== */
+ /* === compute symbolic LL' factorization (unsorted) ==================== */
+ /* ====================================================================== */
+
+ for (j = 0 ; j < n_col ; j = jnext)
+ {
+ DEBUG1 (("\n\n============Front "ID" starting. nfr = "ID"\n", j, nfr)) ;
+
+ /* ================================================================== */
+ /* === garbage collection =========================================== */
+ /* ================================================================== */
+
+ if (pdest + (n_col-j) > pfirst)
+ {
+ /* we might run out ... compact the rows of U */
+
+#ifndef NDEBUG
+ DEBUG0 (("UMF_analyze COMPACTION, j="ID" pfirst="ID"\n",
+ j, pfirst)) ;
+ for (row = 0 ; row < j ; row++)
+ {
+ if (Up [row] != EMPTY)
+ {
+ /* this is a live row of U */
+ DEBUG1 (("Live row: "ID" cols: ", row)) ;
+ p = Up [row] ;
+ ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+ p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+ for ( ; p < p2 ; p++)
+ {
+ DEBUG1 ((ID, Ai [p])) ;
+ ASSERT (p < pfirst) ;
+ ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+ }
+ DEBUG1 (("\n")) ;
+ }
+ }
+ DEBUG1 (("\nStarting to compact:\n")) ;
+#endif
+
+ pdest = 0 ;
+ ncompactions++ ;
+ for (row = 0 ; row < j ; row++)
+ {
+ if (Up [row] != EMPTY)
+ {
+ /* this is a live row of U */
+ DEBUG1 (("Live row: "ID" cols: ", row)) ;
+ ASSERT (row < n_col) ;
+ p = Up [row] ;
+ ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+ p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+ Up [row] = pdest ;
+ for ( ; p < p2 ; p++)
+ {
+ DEBUG1 ((ID, Ai [p])) ;
+ ASSERT (p < pfirst) ;
+ ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+ Ai [pdest++] = Ai [p] ;
+ ASSERT (pdest <= pfirst) ;
+ }
+ DEBUG1 (("\n")) ;
+ }
+ }
+
+#ifndef NDEBUG
+ DEBUG1 (("\nAFTER COMPACTION, j="ID" pfirst="ID"\n", j, pfirst)) ;
+ for (row = 0 ; row < j ; row++)
+ {
+ if (Up [row] != EMPTY)
+ {
+ /* this is a live row of U */
+ DEBUG1 (("Live row: "ID" cols: ", row)) ;
+ p = Up [row] ;
+ ASSERT (Front_ncols [row] > Front_npivcol [row]) ;
+ p2 = p + (Front_ncols [row] - Front_npivcol [row]) ;
+ for ( ; p < p2 ; p++)
+ {
+ DEBUG1 ((ID, Ai [p])) ;
+ ASSERT (p < pfirst) ;
+ ASSERT (Ai [p] > row && Ai [p] < n_col) ;
+ }
+ DEBUG1 (("\n")) ;
+ }
+ }
+#endif
+
+ }
+
+ if (pdest + (n_col-j) > pfirst)
+ {
+ /* Out of memory! This is not supposed to happen ... */
+ /* it can't, if pfirst >= n_col */
+ return (FALSE) ; /* internal error! */
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* is the last front a child of this one? */
+ /* ------------------------------------------------------------------ */
+
+ if (jlast != EMPTY && Link [j] == jlast)
+ {
+ /* yes - create row j by appending to jlast */
+ DEBUG1 (("GOT:last front is child of this one: j "ID" jlast "ID"\n",
+ j, jlast)) ;
+ ASSERT (jlast >= 0 && jlast < j) ;
+
+ Up [j] = Up [jlast] ;
+ Up [jlast] = EMPTY ;
+
+ /* find the parent, delete column j, and update W */
+ parent = n_col ;
+ for (p = Up [j] ; p < pdest ; )
+ {
+ j3 = Ai [p] ;
+ DEBUG1 (("Initial row of U: col "ID" ", j3)) ;
+ ASSERT (j3 >= 0 && j3 < n_col) ;
+ DEBUG1 (("W: "ID" \n", W [j3])) ;
+ ASSERT (W [j3] == Wflag) ;
+ if (j == j3)
+ {
+ DEBUG1 (("Found column j at p = "ID"\n", p)) ;
+ Ai [p] = Ai [--pdest] ;
+ }
+ else
+ {
+ if (j3 < parent)
+ {
+ parent = j3 ;
+ }
+ p++ ;
+ }
+ }
+
+ /* delete jlast from the link list of j */
+ Link [j] = Link [jlast] ;
+
+ ASSERT (Front_nrows [jlast] > Front_npivcol [jlast]) ;
+ thickness = (Front_nrows [jlast] - Front_npivcol [jlast]) ;
+
+ }
+ else
+ {
+ Up [j] = pdest ;
+ parent = n_col ;
+ /* thickness: number of (nonpivotal) rows in frontal matrix j */
+ thickness = 0 ;
+ Wflag = j ;
+ }
+
+ /* ================================================================== */
+ /* === compute row j of A*A' ======================================== */
+ /* ================================================================== */
+
+ /* ------------------------------------------------------------------ */
+ /* flag the diagonal entry in row U, but do not add to pattern */
+ /* ------------------------------------------------------------------ */
+
+ ASSERT (pdest <= pfirst) ;
+ W [j] = Wflag ;
+
+ DEBUG1 (("\nComputing row "ID" of A'*A\n", j)) ;
+ DEBUG2 ((" col: "ID" (diagonal)\n", j)) ;
+
+ /* ------------------------------------------------------------------ */
+ /* find the rows the contribute to this column j */
+ /* ------------------------------------------------------------------ */
+
+ jnext = n_col ;
+ for (knext = krow ; knext < n_row ; knext++)
+ {
+ ASSERT (Ap [knext] < Ap [knext+1]) ;
+
+ ASSERT (Ap [knext] >= pfirst && Ap [knext] <= Ap [n_row]) ;
+ jnext = Ai [Ap [knext]] ;
+ ASSERT (jnext >= j) ;
+ if (jnext != j)
+ {
+ break ;
+ }
+ }
+
+ /* rows krow ... knext-1 all have first column index of j */
+ /* (or are empty) */
+
+ /* row knext has first column index of jnext */
+ /* if knext = n_row, then jnext is n_col */
+ if (knext == n_row)
+ {
+ jnext = n_col ;
+ }
+
+ ASSERT (jnext > j) ;
+ ASSERT (jnext <= n_col) ;
+
+ /* ------------------------------------------------------------------ */
+ /* for each nonzero A (k,j) in column j of A do: */
+ /* ------------------------------------------------------------------ */
+
+ for (k = krow ; k < knext ; k++)
+ {
+ p = Ap [k] ;
+ p2 = Ap [k+1] ;
+ ASSERT (p < p2) ;
+
+ /* merge row k of A into W */
+ DEBUG2 ((" ---- A row "ID" ", k)) ;
+ ASSERT (k >= 0 && k < n_row) ;
+ ASSERT (Ai [p] == j) ;
+ DEBUG2 ((" p "ID" p2 "ID"\n cols:", p, p2)) ;
+ ASSERT (p >= pfirst && p < Ap [n_row]) ;
+ ASSERT (p2 > pfirst && p2 <= Ap [n_row]) ;
+ for ( ; p < p2 ; p++)
+ {
+ /* add to pattern if seen for the first time */
+ col = Ai [p] ;
+ ASSERT (col >= j && col < n_col) ;
+ DEBUG3 ((" "ID, col)) ;
+ if (W [col] != Wflag)
+ {
+ Ai [pdest++] = col ;
+ ASSERT (pdest <= pfirst) ;
+ /* flag this column has having been seen for row j */
+ W [col] = Wflag ;
+ if (col < parent)
+ {
+ parent = col ;
+ }
+ }
+ }
+ DEBUG2 (("\n")) ;
+ thickness++ ;
+
+ }
+
+#ifndef NDEBUG
+ DEBUG3 (("\nRow "ID" of A'A:\n", j)) ;
+ for (p = Up [j] ; p < pdest ; p++)
+ {
+ DEBUG3 ((" "ID, Ai [p])) ;
+ }
+ DEBUG3 (("\n")) ;
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* delete rows up to but not including knext */
+ /* ------------------------------------------------------------------ */
+
+ krow = knext ;
+ pfirst = Ap [knext] ;
+
+ /* we can now use Ai [0..pfirst-1] as workspace for rows of U */
+
+ /* ================================================================== */
+ /* === compute jth row of U ========================================= */
+ /* ================================================================== */
+
+ /* for each nonzero U (k,j) in column j of U (1:j-1,:) do */
+ for (k = Link [j] ; k != EMPTY ; k = Link [k])
+ {
+ /* merge row k of U into W */
+ DEBUG2 ((" ---- U row "ID, k)) ;
+ ASSERT (k >= 0 && k < n_col) ;
+ ASSERT (Up [k] != EMPTY) ;
+ p = Up [k] ;
+ ASSERT (Front_ncols [k] > Front_npivcol [k]) ;
+ p2 = p + (Front_ncols [k] - Front_npivcol [k]) ;
+ DEBUG2 ((" p "ID" p2 "ID"\n cols:", p, p2)) ;
+ ASSERT (p <= pfirst) ;
+ ASSERT (p2 <= pfirst) ;
+ for ( ; p < p2 ; p++)
+ {
+ /* add to pattern if seen for the first time */
+ col = Ai [p] ;
+ ASSERT (col >= j && col < n_col) ;
+ DEBUG3 ((ID, col)) ;
+ if (W [col] != Wflag)
+ {
+ Ai [pdest++] = col ;
+ ASSERT (pdest <= pfirst) ;
+ /* flag this col has having been seen for row j */
+ W [col] = Wflag ;
+ if (col < parent)
+ {
+ parent = col ;
+ }
+ }
+ }
+ DEBUG2 (("\n")) ;
+
+ /* mark the row k as deleted */
+ Up [k] = EMPTY ;
+
+ ASSERT (Front_nrows [k] > Front_npivcol [k]) ;
+ thickness += (Front_nrows [k] - Front_npivcol [k]) ;
+ ASSERT (Front_parent [k] == j) ;
+ }
+
+#ifndef NDEBUG
+ DEBUG3 (("\nRow "ID" of U prior to supercolumn detection:\n", j));
+ for (p = Up [j] ; p < pdest ; p++)
+ {
+ DEBUG3 ((" "ID, Ai [p])) ;
+ }
+ DEBUG3 (("\n")) ;
+#endif
+
+ /* ================================================================== */
+ /* === quicky mass elimination ====================================== */
+ /* ================================================================== */
+
+ /* this code detects some supernodes, but it might miss */
+ /* some because the elimination tree (created on the fly) */
+ /* is not yet post-ordered, and because the pattern of A'*A */
+ /* is also computed on the fly. */
+
+ /* j2 is incremented because the pivot columns are not stored */
+
+ for (j2 = j+1 ; j2 < jnext ; j2++)
+ {
+ ASSERT (j2 >= 0 && j2 < n_col) ;
+ if (W [j2] != Wflag || Link [j2] != EMPTY)
+ {
+ break ;
+ }
+ }
+
+ /* the loop above terminated with j2 at the first non-supernode */
+ DEBUG1 (("jnext = "ID"\n", jnext)) ;
+ ASSERT (j2 <= jnext) ;
+ jnext = j2 ;
+ j2-- ;
+ DEBUG1 (("j2 = "ID"\n", j2)) ;
+ ASSERT (j2 < n_col) ;
+
+ npivots = j2-j+1 ;
+
+ /* rows j:j2 have the same nonzero pattern, except for columns j:j2-1 */
+
+ if (j2 > j)
+ {
+ /* supernode detected, prune the pattern of new row j */
+ ASSERT (parent == j+1) ;
+ ASSERT (j2 < n_col) ;
+ DEBUG1 (("Supernode detected, j "ID" to j2 "ID"\n", j, j2)) ;
+
+ parent = n_col ;
+ p2 = pdest ;
+ pdest = Up [j] ;
+ for (p = Up [j] ; p < p2 ; p++)
+ {
+ col = Ai [p] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (W [col] == Wflag) ;
+ if (col > j2)
+ {
+ /* keep this col in the pattern of the new row j */
+ Ai [pdest++] = col ;
+ if (col < parent)
+ {
+ parent = col ;
+ }
+ }
+ }
+ }
+
+ DEBUG1 (("Parent ["ID"] = "ID"\n", j, parent)) ;
+ ASSERT (parent > j2) ;
+
+ if (parent == n_col)
+ {
+ /* this front has no parent - it is the root of a subtree */
+ parent = EMPTY ;
+ }
+
+#ifndef NDEBUG
+ DEBUG3 (("\nFinal row "ID" of U after supercolumn detection:\n", j)) ;
+ for (p = Up [j] ; p < pdest ; p++)
+ {
+ ASSERT (Ai [p] >= 0 && Ai [p] < n_col) ;
+ DEBUG3 ((" "ID" ("ID")", Ai [p], W [Ai [p]])) ;
+ ASSERT (W [Ai [p]] == Wflag) ;
+ }
+ DEBUG3 (("\n")) ;
+#endif
+
+ /* ================================================================== */
+ /* === frontal matrix =============================================== */
+ /* ================================================================== */
+
+ /* front has Front_npivcol [j] pivot columns */
+ /* entire front is Front_nrows [j] -by- Front_ncols [j] */
+ /* j is first column in the front */
+
+ npivcol = npivots ;
+ fallrows = thickness ;
+ fallcols = npivots + pdest - Up [j] ;
+
+ /* number of pivots in the front (rows and columns) */
+ fpiv = MIN (npivcol, fallrows) ;
+
+ /* size of contribution block */
+ frows = fallrows - fpiv ;
+ fcols = fallcols - fpiv ;
+
+ if (frows == 0 || fcols == 0)
+ {
+ /* front has no contribution block and thus needs no parent */
+ Up [j] = EMPTY ;
+ parent = EMPTY ;
+ }
+
+ Front_npivcol [j] = npivots ;
+ Front_nrows [j] = fallrows ;
+ Front_ncols [j] = fallcols ;
+ Front_parent [j] = parent ;
+ ASSERT (npivots > 0) ;
+
+ /* Front_parent [j] is the first column of the parent frontal matrix */
+
+ DEBUG1 (("\n\n==== Front "ID", pivot columns "ID":"ID" all front: "ID
+ "-by-"ID"\n", j, j,j+npivots-1, Front_nrows [j], Front_ncols [j])) ;
+ nfr++ ;
+
+ /* ================================================================== */
+ /* === prepare this row for its parent ============================== */
+ /* ================================================================== */
+
+ if (parent != EMPTY)
+ {
+ Link [j] = Link [parent] ;
+ Link [parent] = j ;
+ }
+
+ ASSERT (jnext > j) ;
+
+ jlast = j ;
+ }
+
+ /* ====================================================================== */
+ /* === scan the fronts ================================================== */
+ /* ====================================================================== */
+
+ *nfr_out = nfr ;
+
+ /* use Ap for Front_child and use Link for Front_sibling [ */
+ Front_child = Ap ;
+ Front_sibling = Link ;
+
+ /* use W for Front_maxfr [ */
+ Front_maxfr = W ;
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ Front_child [j] = EMPTY ;
+ Front_sibling [j] = EMPTY ;
+ Front_maxfr [j] = EMPTY ;
+ }
+
+ DEBUG1 (("\n\n========================================FRONTS:\n")) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find max front size for tree rooted at node j, for each front j */
+ /* ---------------------------------------------------------------------- */
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ DEBUG1 ((""ID" : npiv "ID" nrows "ID" ncols "ID" parent "ID" ",
+ j, Front_npivcol [j], Front_nrows [j], Front_ncols [j],
+ Front_parent [j])) ;
+ if (Front_npivcol [j] > 0)
+ {
+ /* this is a frontal matrix */
+ parent = Front_parent [j] ;
+ frsize = Front_nrows [j] * Front_ncols [j] ;
+
+ DEBUG1 ((" a front, frsize "ID", true parent: "ID"\n", frsize,
+ parent)) ;
+
+ Front_maxfr [j] = MAX (Front_maxfr [j], frsize) ;
+ DEBUG1 (("Front_maxfr [j = "ID"] = "ID"\n", j, Front_maxfr [j])) ;
+
+ if (parent != EMPTY)
+ {
+ ASSERT (Front_npivcol [parent] > 0) ;
+ ASSERT (parent > j) ;
+
+ /* find the maximum frontsize of self and children */
+ Front_maxfr [parent] = MAX (Front_maxfr [parent],
+ Front_maxfr [j]) ;
+ DEBUG1 (("Front_maxfr [parent = "ID"] = "ID"\n",
+ parent, Front_maxfr [parent]));
+ }
+ }
+ DEBUG1 (("\n")) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* place the children in link lists - bigger fronts will tend to be last */
+ /* ---------------------------------------------------------------------- */
+
+ for (j = n_col-1 ; j >= 0 ; j--)
+ {
+ if (Front_npivcol [j] > 0)
+ {
+ /* this is a frontal matrix */
+ parent = Front_parent [j] ;
+ if (parent != EMPTY)
+ {
+ /* place the front in link list of the children its parent */
+ Front_sibling [j] = Front_child [parent] ;
+ Front_child [parent] = j ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ DEBUG1 (("\n\n========================================FRONTS (again):\n")) ;
+ nfr2 = 0 ;
+ for (j = 0 ; j < n_col ; j++)
+ {
+ if (Front_npivcol [j] > 0)
+ {
+ DEBUG1 (( ""ID" : nfr "ID" npiv "ID" nrows "ID" ncols "ID
+ " parent "ID" maxfr "ID"\n", j, nfr2,
+ Front_npivcol [j], Front_nrows [j], Front_ncols [j],
+ Front_parent [j], Front_maxfr [j])) ;
+
+ /* this is a frontal matrix */
+
+ /* dump the link list of children */
+ DEBUG1 ((" Children: ")) ;
+ for (f = Front_child [j] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ DEBUG1 ((ID, f)) ;
+ ASSERT (Front_parent [f] == j) ;
+ }
+ DEBUG1 (("\n")) ;
+
+ parent = Front_parent [j] ;
+ if (parent != EMPTY)
+ {
+ /* Assert that the parent front can absorb the child element */
+ ASSERT (Front_npivcol [parent] > 0) ;
+ ASSERT ((Front_nrows [j] - Front_npivcol [j])
+ <= Front_nrows [parent]) ;
+ ASSERT ((Front_ncols [j] - Front_npivcol [j])
+ <= Front_ncols [parent]) ;
+ }
+ nfr2++ ;
+ }
+ }
+ ASSERT (nfr == nfr2) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* Order the front tree via depth-first-search */
+ /* ---------------------------------------------------------------------- */
+
+ for (i = 0 ; i < n_col ; i++)
+ {
+ if (Front_npivcol [i] > 0 && Front_child [i] != EMPTY)
+ {
+
+#ifndef NDEBUG
+ DEBUG1 (("Before partial sort, front "ID"\n", i)) ;
+ nchild = 0 ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ DEBUG1 ((" "ID" "ID"\n", f, Front_maxfr [f])) ;
+ nchild++ ;
+ }
+#endif
+
+ /* find the biggest front in the child list */
+ fprev = EMPTY ;
+ maxfrsize = EMPTY ;
+ bigfprev = EMPTY ;
+ bigf = EMPTY ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ frsize = Front_maxfr [f] ;
+ if (frsize >= maxfrsize)
+ {
+ /* this is the biggest seen so far */
+ maxfrsize = frsize ;
+ bigfprev = fprev ;
+ bigf = f ;
+ }
+ fprev = f ;
+ }
+ ASSERT (bigf != EMPTY) ;
+
+ fnext = Front_sibling [bigf] ;
+
+ DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID" fprev "
+ ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
+
+ if (fnext != EMPTY)
+ {
+ /* if fnext is EMPTY, then bigf is already at the end of list */
+
+ if (bigfprev == EMPTY)
+ {
+ /* delete bigf from the front of the list */
+ Front_child [i] = fnext ;
+ }
+ else
+ {
+ /* delete bigf from the middle of the list */
+ Front_sibling [bigfprev] = fnext ;
+ }
+
+ /* put bigf at the end of the list */
+ Front_sibling [bigf] = EMPTY ;
+ ASSERT (Front_child [i] != EMPTY) ;
+ ASSERT (fprev != bigf) ;
+ ASSERT (fprev != EMPTY) ;
+ Front_sibling [fprev] = bigf ;
+ }
+
+#ifndef NDEBUG
+ DEBUG1 (("After partial sort, front "ID"\n", i)) ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ DEBUG1 ((" "ID" "ID"\n", f, Front_maxfr [f])) ;
+ ASSERT (Front_npivcol [f] > 0) ;
+ nchild-- ;
+ }
+ ASSERT (nchild == 0) ;
+#endif
+
+ }
+ }
+
+ /* Front_maxfr no longer needed ] */
+
+ /* ---------------------------------------------------------------------- */
+ /* postorder the supernodal column elimination tree */
+ /* ---------------------------------------------------------------------- */
+
+ /* use W for Front_order ( */
+ Front_order = W ;
+
+ /* use Ai as Stack for UMF_order_front_tree [ */
+ Stack = Ai ;
+
+ for (i = 0 ; i < n_col ; i++)
+ {
+ Front_order [i] = EMPTY ;
+ }
+
+#ifndef NDEBUG
+ UMF_nbug = n_col ; /* frontal id's are in the range 0..n_col-1 */
+ UMF_fbug = nfr ; /* total number of frontal matrices */
+#endif
+
+ k = 0 ;
+ for (i = 0 ; i < n_col ; i++)
+ {
+ if (Front_parent [i] == EMPTY && Front_npivcol [i] != 0)
+ {
+ DEBUG1 (("Root of front tree "ID"\n", i)) ;
+ k = UMF_order_front_tree (i, k, Front_child, Front_sibling,
+ Front_order, Stack) ;
+ }
+ }
+
+ /* Stack no longer needed ] */
+ /* Front_child, Front_sibling no longer needed ] */
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the column permutation (return in Up) */
+ /* ---------------------------------------------------------------------- */
+
+ /* Front_order [i] = k means that front i is kth front in the new order. */
+ /* i is in the range 0 to n_col-1, and k is in the range 0 to nfr-1 */
+
+ /* Use Ai as workspace for Winv [ */
+ Winv = Ai ;
+ for (k = 0 ; k < nfr ; k++)
+ {
+ Winv [k] = EMPTY ;
+ }
+
+ /* compute the inverse of Front_order, so that Winv [k] = i */
+ /* if Front_order [i] = k */
+
+ DEBUG1 (("\n\nComputing output column permutation:\n")) ;
+ for (i = 0 ; i < n_col ; i++)
+ {
+ k = Front_order [i] ;
+ if (k != EMPTY)
+ {
+ DEBUG1 (("Front "ID" new order: "ID"\n", i, k)) ;
+ ASSERT (k >= 0 && k < nfr) ;
+ ASSERT (Winv [k] == EMPTY) ;
+ Winv [k] = i ;
+ }
+ }
+
+ /* Use Up as output permutation */
+ kk = 0 ;
+ for (k = 0 ; k < nfr ; k++)
+ {
+ i = Winv [k] ;
+ DEBUG1 (("Old Front "ID" New Front "ID" npivots "ID" nrows "ID" ncols "ID"\n",
+ i, k, Front_npivcol [i], Front_nrows [i], Front_ncols [i])) ;
+ ASSERT (i >= 0 && i < n_col) ;
+ ASSERT (Front_npivcol [i] > 0) ;
+ for (npiv = 0 ; npiv < Front_npivcol [i] ; npiv++)
+ {
+ Up [kk] = i + npiv ;
+ DEBUG1 ((" Cperm ["ID"] = "ID"\n", kk, Up [kk])) ;
+ kk++ ;
+ }
+ }
+ ASSERT (kk == n_col) ;
+
+ /* Winv no longer needed ] */
+
+ /* ---------------------------------------------------------------------- */
+ /* apply the postorder traversal to renumber the frontal matrices */
+ /* ---------------------------------------------------------------------- */
+
+ /* use Ai as workspace */
+
+ UMF_apply_order (Front_npivcol, Front_order, Ai, n_col, nfr) ;
+ UMF_apply_order (Front_nrows, Front_order, Ai, n_col, nfr) ;
+ UMF_apply_order (Front_ncols, Front_order, Ai, n_col, nfr) ;
+ UMF_apply_order (Front_parent, Front_order, Ai, n_col, nfr) ;
+
+ /* fix the parent to refer to the new numbering */
+ for (i = 0 ; i < nfr ; i++)
+ {
+ parent = Front_parent [i] ;
+ if (parent != EMPTY)
+ {
+ ASSERT (parent >= 0 && parent < n_col) ;
+ ASSERT (Front_order [parent] >= 0 && Front_order [parent] < nfr) ;
+ Front_parent [i] = Front_order [parent] ;
+ }
+ }
+
+ /* Front_order longer needed ) */
+
+#ifndef NDEBUG
+ DEBUG1 (("\nFinal frontal matrices:\n")) ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ DEBUG1 (("Final front "ID": npiv "ID" nrows "ID" ncols "ID" parent "
+ ID"\n", i, Front_npivcol [i], Front_nrows [i],
+ Front_ncols [i], Front_parent [i])) ;
+ }
+#endif
+
+ *p_ncompactions = ncompactions ;
+ return (TRUE) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_apply_order.c b/src/sparse-matrix/umfpack/umf_apply_order.c
new file mode 100644
index 0000000..f7ced0e
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_apply_order.c
@@ -0,0 +1,42 @@
+/* ========================================================================== */
+/* === UMF_apply_order ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Apply post-ordering of supernodal elimination tree.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_apply_order
+(
+ Int Front [ ],
+ const Int Order [ ],
+ Int Temp [ ],
+ Int n_col,
+ Int nfr
+)
+{
+ Int i, k ;
+ for (i = 0 ; i < n_col ; i++)
+ {
+ k = Order [i] ;
+ if (k != EMPTY)
+ {
+ Temp [k] = Front [i] ;
+ }
+ }
+
+ for (k = 0 ; k < nfr ; k++)
+ {
+ Front [k] = Temp [k] ;
+ }
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_assemble.c b/src/sparse-matrix/umfpack/umf_assemble.c
new file mode 100644
index 0000000..57a5623
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_assemble.c
@@ -0,0 +1,1037 @@
+/* ========================================================================== */
+/* === UMF_assemble ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Degree update and numerical assembly */
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+
+GLOBAL void UMF_assemble
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int e, i, row, col, i2, nrows, ncols, f, tpi, extcdeg, extrdeg, rdeg0,
+ cdeg0, son_list, next, scan_pivrow, scan_pivcol, nrows_to_assemble,
+ ncols_to_assemble, ngetrows, j, j2,
+ nrowsleft, /* number of rows remaining in C */
+ ncolsleft, /* number of columns remaining in C */
+ prior_Lson, prior_Uson, *E, *Cols, *Rows, *Wm, *Woo,
+ *Row_tuples, *Row_degree, *Row_tlen,
+ *Col_tuples, *Col_degree, *Col_tlen ;
+ Unit *Memory, *p ;
+ Element *ep ;
+ Tuple *tp, *tp1, *tp2, *tpend ;
+
+ Entry
+ *C, /* a pointer into the contribution block */
+ *Fx, /* Fx [0..fnrows_max-1, 0..fncols_max-1] working array*/
+ *Fcol, /* a column of F */
+ *Frow ; /* a row of F */
+
+ Int
+ *Frows, /* Frows [0.. ]: row indices of F */
+ *Fcols, /* Fcols [0.. ]: column indices of F */
+ *Frpos,
+ *Fcpos,
+ fnrows, /* number of rows in contribution block in F */
+ fncols ; /* number of columns in contribution block in F */
+
+#ifndef NDEBUG
+ Int j3, n_row, n_col ;
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ DEBUG3 (("::Assemble SCANS 1-4\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ fncols = Work->fncols ;
+ fnrows = Work->fnrows ;
+ Fcols = Work->Fcols ;
+ Frows = Work->Frows ;
+ Fcpos = Work->Fcpos ;
+ Frpos = Work->Frpos ;
+ Fx = Work->Fx ;
+ Col_degree = Numeric->Cperm ;
+ Row_degree = Numeric->Rperm ;
+ Row_tuples = Numeric->Uip ;
+ Row_tlen = Numeric->Uilen ;
+ Col_tuples = Numeric->Lip ;
+ Col_tlen = Numeric->Lilen ;
+ E = Work->E ;
+ Memory = Numeric->Memory ;
+ Wm = Work->Wm ;
+ Woo = Work->Woo ; /* must be of size at least fnrows_max */
+ rdeg0 = Work->rdeg0 ;
+ cdeg0 = Work->cdeg0 ;
+
+#ifndef NDEBUG
+ DEBUG6 (("============================================\n")) ;
+ DEBUG6 (("Degree update, assembly.\n")) ;
+ DEBUG6 (("pivot row pattern: fncols="ID"\n", fncols)) ;
+ for (j3 = 0 ; j3 < fncols ; j3++) DEBUG6 ((ID, Fcols [j3])) ;
+ DEBUG6 (("\npivot col pattern: fnrows="ID"\n", fnrows)) ;
+ for (j3 = 0 ; j3 < fnrows ; j3++) DEBUG6 ((ID, Frows [j3])) ;
+ DEBUG6 (("\n")) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the largest actual frontal matrix size */
+ /* ---------------------------------------------------------------------- */
+
+ Numeric->maxfrsize = MAX (Numeric->maxfrsize,
+ (fnrows + Work->fnpiv) * (fncols + Work->fnpiv)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* assemble from prior elements into the current frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG2 (("New assemble start [\n")) ;
+
+ /* Currently no rows or columns are marked. No elements are scanned, */
+ /* that is, (ep->next == EMPTY) is true for all elements */
+
+ son_list = 0 ; /* start creating son_list [ */
+
+ /* ---------------------------------------------------------------------- */
+ /* determine if most recent element is Lson or Uson of current front */
+ /* ---------------------------------------------------------------------- */
+
+ if (!Work->do_extend)
+ {
+ prior_Uson = ( Work->pivcol_in_front && !Work->pivrow_in_front) ;
+ prior_Lson = (!Work->pivcol_in_front && Work->pivrow_in_front) ;
+ if (prior_Uson || prior_Lson)
+ {
+ e = Work->prior_element ;
+ if (e != EMPTY)
+ {
+ ASSERT (E [e]) ;
+ p = Memory + E [e] ;
+ ep = (Element *) p ;
+ ep->next = son_list ;
+ son_list = e ;
+#ifndef NDEBUG
+ DEBUG2 (("e "ID" is Prior son "ID" "ID"\n",
+ e, prior_Uson, prior_Lson)) ;
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+ ASSERT (E [e]) ;
+ }
+ }
+ }
+ Work->prior_element = EMPTY ;
+
+ /* ---------------------------------------------------------------------- */
+ /* SCAN1-row: scan the element lists of each new row in the pivot col */
+ /* and compute the external column degree for each frontal */
+ /* ---------------------------------------------------------------------- */
+
+ scan_pivrow = Work->scan_pivrow ;
+
+ for (i2 = Work->fscan_row ; i2 < fnrows || scan_pivrow ; )
+ {
+ /* Get a row */
+ if (scan_pivrow)
+ {
+ /* pivot row is new to this front. Scan it */
+ row = Work->pivrow ;
+ scan_pivrow = FALSE ;
+ }
+ else
+ {
+ row = Frows [i2++] ;
+ }
+
+ DEBUG6 (("SCAN1-row: "ID"\n", row)) ;
+#ifndef NDEBUG
+ UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ tpi = Row_tuples [row] ;
+ if (!tpi) continue ;
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Row_tlen [row] ;
+ 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) ;
+ Rows = ((Int *) p) + ep->ncols ;
+ if (Rows [f] == EMPTY) continue ; /* row already assembled */
+ ASSERT (row == Rows [f]) ;
+
+ if (ep->cdeg < cdeg0)
+ {
+ /* first time seen in scan1-row */
+ ep->cdeg = ep->nrowsleft + cdeg0 ;
+ DEBUG6 (("e "ID" First seen: cdeg: "ID" ", e, ep->cdeg-cdeg0)) ;
+ ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
+ }
+
+ ep->cdeg-- ; /* decrement external column degree */
+ DEBUG6 (("e "ID" New ext col deg: "ID"\n", e, ep->cdeg - cdeg0)) ;
+
+ /* this element is not yet in the new son list */
+ if (ep->cdeg == cdeg0 && ep->next == EMPTY)
+ {
+ /* A new LUson or Uson has been found */
+ ep->next = son_list ;
+ son_list = e ;
+ }
+
+ ASSERT (ep->cdeg >= cdeg0) ;
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ Row_tlen [row] = tp2 - tp1 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* SCAN1-col: scan the element lists of each new col in the pivot row */
+ /* and compute the external row degree for each frontal */
+ /* ---------------------------------------------------------------------- */
+
+ scan_pivcol = Work->scan_pivcol ;
+
+ for (j2 = Work->fscan_col ; j2 < fncols || scan_pivcol ; )
+ {
+ /* Get a column */
+ if (scan_pivcol)
+ {
+ /* pivot col is new to this front. Scan it */
+ col = Work->pivcol ;
+ scan_pivcol = FALSE ;
+ }
+ else
+ {
+ col = Fcols [j2++] ;
+ }
+ ASSERT (col >= 0 && col < n_col) ;
+
+ DEBUG6 (("SCAN 1-col: "ID"\n", col)) ;
+#ifndef NDEBUG
+ UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ tpi = Col_tuples [col] ;
+ if (!tpi) continue ;
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Col_tlen [col] ;
+ 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 ; /* column already assembled */
+ ASSERT (col == Cols [f]) ;
+
+ if (ep->rdeg < rdeg0)
+ {
+ /* first time seen in scan1-col */
+ ep->rdeg = ep->ncolsleft + rdeg0 ;
+ DEBUG6 (("e "ID" First seen: rdeg: "ID" ", e, ep->rdeg-rdeg0)) ;
+ ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
+ }
+
+ ep->rdeg-- ; /* decrement external row degree */
+ DEBUG6 (("e "ID" New ext row degree: "ID"\n", e, ep->rdeg-rdeg0)) ;
+
+ if (ep->rdeg == rdeg0 && ep->next == EMPTY)
+ {
+ /* A new LUson or Lson has been found */
+ ep->next = son_list ;
+ son_list = e ;
+ }
+
+ ASSERT (ep->rdeg >= rdeg0) ;
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ Col_tlen [col] = tp2 - tp1 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* assemble new sons via full scans */
+ /* ---------------------------------------------------------------------- */
+
+ next = EMPTY ;
+
+ for (e = son_list ; e > 0 ; e = next)
+ {
+ ASSERT (e > 0 && e <= Work->nel && E [e]) ;
+ p = Memory + E [e] ;
+ DEBUG2 (("New son: "ID"\n", e)) ;
+#ifndef NDEBUG
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+ GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ;
+ nrowsleft = ep->nrowsleft ;
+ ncolsleft = ep->ncolsleft ;
+ next = ep->next ;
+ ep->next = EMPTY ;
+
+ extrdeg = (ep->rdeg < rdeg0) ? ncolsleft : (ep->rdeg - rdeg0) ;
+ extcdeg = (ep->cdeg < cdeg0) ? nrowsleft : (ep->cdeg - cdeg0) ;
+ ncols_to_assemble = ncolsleft - extrdeg ;
+ nrows_to_assemble = nrowsleft - extcdeg ;
+
+ if (extrdeg == 0 && extcdeg == 0)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* this is an LUson - assemble an entire contribution block */
+ /* -------------------------------------------------------------- */
+
+ DEBUG6 (("LUson found: "ID"\n", e)) ;
+
+ if (nrows == nrowsleft)
+ {
+ /* ---------------------------------------------------------- */
+ /* no rows assembled out of this LUson yet */
+ /* ---------------------------------------------------------- */
+
+ /* compute the compressed column offset vector*/
+ /* [ use Wm [0..nrows-1] for offsets */
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ Row_degree [row] -= ncolsleft ;
+ Wm [i] = Frpos [row] ;
+ }
+
+ if (ncols == ncolsleft)
+ {
+ /* ------------------------------------------------------ */
+ /* no rows or cols assembled out of LUson yet */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ Col_degree [col] -= nrowsleft ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ /* Fcol [Wm [i]] += C [i] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [i]) ;
+ }
+ C += nrows ;
+ }
+ }
+ else
+ {
+ /* ------------------------------------------------------ */
+ /* only cols have been assembled out of LUson */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+ Col_degree [col] -= nrowsleft ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ /* Fcol [Wm [i]] += C [i] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [i]) ;
+ }
+ }
+ C += nrows ;
+ }
+ }
+ /* ] done using Wm [0..nrows-1] for offsets */
+ }
+ else
+ {
+ /* ---------------------------------------------------------- */
+ /* some rows have been assembled out of this LUson */
+ /* ---------------------------------------------------------- */
+
+ /* compute the compressed column offset vector*/
+ /* [ use Woo,Wm [0..nrowsleft-1] for offsets */
+ ngetrows = 0 ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0)
+ {
+ Row_degree [row] -= ncolsleft ;
+ Woo [ngetrows] = i ;
+ Wm [ngetrows++] = Frpos [row] ;
+ }
+ }
+ ASSERT (ngetrows == nrowsleft) ;
+
+ if (ncols == ncolsleft)
+ {
+ /* ------------------------------------------------------ */
+ /* only rows have been assembled out of this LUson */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ Col_degree [col] -= nrowsleft ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrowsleft ; i++)
+ {
+ /* Fcol [Wm [i]] += C [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [Woo [i]]) ;
+ }
+ C += nrows ;
+ }
+
+ }
+ else
+ {
+ /* ------------------------------------------------------ */
+ /* both rows and columns have been assembled out of LUson */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+ Col_degree [col] -= nrowsleft ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrowsleft ; i++)
+ {
+ /* Fcol [Wm [i]] += C [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [Woo [i]]) ;
+ }
+ }
+ C += nrows ;
+ }
+ }
+ /* ] done using Woo,Wm [0..nrowsleft-1] */
+ }
+
+ /* deallocate the element: remove from ordered list */
+ UMF_mem_free_tail_block (Numeric, E [e]) ;
+ E [e] = 0 ;
+
+ }
+ else if (extcdeg == 0)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* this is a Uson - assemble all possible columns */
+ /* -------------------------------------------------------------- */
+
+ DEBUG6 (("New USON: "ID"\n", e)) ;
+ ASSERT (extrdeg > 0) ;
+
+ DEBUG6 (("New uson "ID" cols to do "ID"\n", e, ncols_to_assemble)) ;
+
+ if (ncols_to_assemble > 0)
+ {
+
+ if (nrows == nrowsleft)
+ {
+ /* ------------------------------------------------------ */
+ /* no rows have been assembled out of this Uson yet */
+ /* ------------------------------------------------------ */
+
+ /* compute the compressed column offset vector */
+ /* [ use Wm [0..nrows-1] for offsets */
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ Row_degree [row] -= ncols_to_assemble ;
+ Wm [i] = Frpos [row] ;
+ }
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if ((col >= 0) && (Fcpos [col] >= 0))
+ {
+ Col_degree [col] -= nrowsleft ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ /* Fcol [Wm [i]] += C [i] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [i]) ;
+ }
+ /* flag the column as assembled from Uson */
+ Cols [j] = EMPTY ;
+ }
+ C += nrows ;
+ }
+ /* ] done using Wm [0..nrows-1] for offsets */
+ }
+ else
+ {
+ /* ------------------------------------------------------ */
+ /* some rows have been assembled out of this Uson */
+ /* ------------------------------------------------------ */
+
+ /* compute the compressed column offset vector*/
+ /* [ use Woo,Wm [0..nrows-1] for offsets */
+ ngetrows = 0 ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0)
+ {
+ Row_degree [row] -= ncols_to_assemble ;
+ ASSERT (row < n_row && Frpos [row] >= 0) ;
+ Woo [ngetrows] = i ;
+ Wm [ngetrows++] = Frpos [row] ;
+ }
+ }
+ ASSERT (ngetrows == nrowsleft) ;
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if ((col >= 0) && (Fcpos [col] >= 0))
+ {
+ Col_degree [col] -= nrowsleft ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrowsleft ; i++)
+ {
+ /* Fcol [Wm [i]] += C [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [Woo [i]]) ;
+ }
+ /* flag the column as assembled from Uson */
+ Cols [j] = EMPTY ;
+ }
+ C += nrows ;
+ }
+ /* ] done using Woo,Wm */
+ }
+ ep->ncolsleft = extrdeg ;
+ }
+
+ }
+ else
+ {
+
+ /* -------------------------------------------------------------- */
+ /* this is an Lson - assemble all possible rows */
+ /* -------------------------------------------------------------- */
+
+ DEBUG6 (("New LSON: "ID"\n", e)) ;
+ ASSERT (extrdeg == 0 && extcdeg > 0) ;
+
+ DEBUG6 (("New lson "ID" rows to do "ID"\n", e, nrows_to_assemble)) ;
+
+ if (nrows_to_assemble > 0)
+ {
+
+ /* compute the compressed column offset vector */
+ /* [ use Woo,Wm [0..nrows-1] for offsets */
+ ngetrows = 0 ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ if ((row >= 0) && (Frpos [row] >= 0))
+ {
+ ASSERT (row < n_row) ;
+ Row_degree [row] -= ncolsleft ;
+ Woo [ngetrows] = i ;
+ Wm [ngetrows++] = Frpos [row] ;
+ /* flag the row as assembled from the Lson */
+ Rows [i] = EMPTY ;
+ }
+ }
+ ASSERT (nrowsleft - ngetrows == extcdeg) ;
+ ASSERT (ngetrows == nrows_to_assemble) ;
+
+ if (ncols == ncolsleft)
+ {
+ /* ------------------------------------------------------ */
+ /* no columns assembled out this Lson yet */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ Col_degree [col] -= nrows_to_assemble ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrows_to_assemble ; i++)
+ {
+ /* Fcol [Wm [i]] += C [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [Woo [i]]) ;
+ }
+ C += nrows ;
+ }
+ }
+ else
+ {
+ /* ------------------------------------------------------ */
+ /* some columns have been assembled out of this Lson */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ ASSERT (col < n_col) ;
+ if (col >= 0)
+ {
+ Col_degree [col] -= nrows_to_assemble ;
+ Fcol = Fx + Fcpos [col] ;
+ for (i = 0 ; i < nrows_to_assemble ; i++)
+ {
+ /* Fcol [Wm [i]] += C [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], C [Woo [i]]) ;
+ }
+ }
+ C += nrows ;
+ }
+ }
+
+ /* ] done using Woo,Wm */
+
+ ep->nrowsleft = extcdeg ;
+ }
+ }
+ }
+
+ /* Note that garbage collection, and build tuples */
+ /* both destroy the son list. */
+
+ /* ] son_list now empty */
+
+ /* ---------------------------------------------------------------------- */
+ /* If frontal matrix extended, assemble old L/Usons from new rows/cols */
+ /* ---------------------------------------------------------------------- */
+
+ /* ---------------------------------------------------------------------- */
+ /* SCAN2-row: assemble rows of old Lsons from the new rows */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG7 (("Current frontal matrix: (prior to scan2-row)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ if (Work->do_scan2row)
+ {
+
+ scan_pivrow = Work->scan_pivrow ;
+
+ for (i2 = Work->fscan_row ; i2 < fnrows || scan_pivrow ; )
+ {
+ /* Get a row */
+ if (scan_pivrow)
+ {
+ /* pivot row is new to this front. Scan it */
+ row = Work->pivrow ;
+ scan_pivrow = FALSE ;
+ }
+ else
+ {
+ row = Frows [i2++] ;
+ }
+ ASSERT (row >= 0 && row < n_row) ;
+
+#ifndef NDEBUG
+ DEBUG6 (("SCAN2-row: "ID"\n", row)) ;
+ UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ tpi = Row_tuples [row] ;
+ if (!tpi) continue ;
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Row_tlen [row] ;
+ 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 ; /* row already assembled */
+ ASSERT (row == Rows [f] && row >= 0 && row < n_row) ;
+
+ if (ep->rdeg == rdeg0)
+ {
+ /* ------------------------------------------------------ */
+ /* this is an old Lson - assemble just one row */
+ /* ------------------------------------------------------ */
+
+ /* flag the row as assembled from the Lson */
+ Rows [f] = EMPTY ;
+
+ nrows = ep->nrows ;
+ ncols = ep->ncols ;
+ p += UNITS (Int, ncols + nrows) ;
+ C = ((Entry *) p) + f ;
+
+ DEBUG6 (("Old LSON: "ID"\n", e)) ;
+#ifndef NDEBUG
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+ nrowsleft = ep->nrowsleft ;
+ ncolsleft = ep->ncolsleft ;
+
+ Frow = Fx + Frpos [row] ;
+ DEBUG6 (("LSON found (in scan2-row): "ID"\n", e)) ;
+
+ Row_degree [row] -= ncolsleft ;
+
+ if (ncols == ncolsleft)
+ {
+ /* -------------------------------------------------- */
+ /* no columns assembled out this Lson yet */
+ /* -------------------------------------------------- */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ Col_degree [col] -- ;
+ /* Frow [Fcpos [col]] += *C ; */
+ ASSEMBLE (Frow [Fcpos [col]], *C) ;
+ C += nrows ;
+ }
+ }
+ else
+ {
+ /* -------------------------------------------------- */
+ /* some columns have been assembled out of this Lson */
+ /* -------------------------------------------------- */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+ ASSERT (col < n_col) ;
+ Col_degree [col] -- ;
+ /* Frow [Fcpos [col]] += *C ; */
+ ASSEMBLE (Frow [Fcpos [col]], *C) ;
+ }
+ C += nrows ;
+ }
+ }
+ ep->nrowsleft-- ;
+ ASSERT (ep->nrowsleft > 0) ;
+ }
+ else
+ {
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ }
+ Row_tlen [row] = tp2 - tp1 ;
+
+#ifndef NDEBUG
+ DEBUG7 (("row assembled in scan2-row: "ID"\n", row)) ;
+ if (row != Work->pivrow)
+ {
+ UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+ }
+ DEBUG7 (("Current frontal matrix: (scan 1b)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* SCAN2-col: assemble columns of old Usons from the new columns */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG7 (("Current frontal matrix: (prior to scan2-col)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ if (Work->do_scan2col)
+ {
+
+ scan_pivcol = Work->scan_pivcol ;
+
+ for (j2 = Work->fscan_col ; j2 < fncols || scan_pivcol ; )
+ {
+ /* Get a column */
+ if (scan_pivcol)
+ {
+ /* pivot col is new to this front. Scan it */
+ col = Work->pivcol ;
+ scan_pivcol = FALSE ;
+ }
+ else
+ {
+ col = Fcols [j2++] ;
+ }
+ ASSERT (col >= 0 && col < n_col) ;
+
+ DEBUG6 (("SCAN2-col: "ID"\n", col)) ;
+#ifndef NDEBUG
+ UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ tpi = Col_tuples [col] ;
+ if (!tpi) continue ;
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Col_tlen [col] ;
+ 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 ; /* column already assembled */
+ }
+ ASSERT (col == Cols [f] && col >= 0 && col < n_col) ;
+
+ if (ep->cdeg == cdeg0)
+ {
+
+ /* ------------------------------------------------------ */
+ /* this is an old Uson - assemble just one column */
+ /* ------------------------------------------------------ */
+
+ /* flag the column as assembled from the Uson */
+ Cols [f] = EMPTY ;
+
+ nrows = ep->nrows ;
+ ncols = ep->ncols ;
+ Rows = Cols + ncols ;
+ p += UNITS (Int, ep->ncols + nrows) ;
+ C = ((Entry *) p) + f * nrows ;
+
+ DEBUG6 (("Old USON: "ID"\n", e)) ;
+#ifndef NDEBUG
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+ nrowsleft = ep->nrowsleft ;
+ ncolsleft = ep->ncolsleft ;
+
+ Fcol = Fx + Fcpos [col] ;
+ DEBUG6 (("USON found (in scan2-col): "ID"\n", e)) ;
+
+ Col_degree [col] -= nrowsleft ;
+
+ if (nrows == nrowsleft)
+ {
+ /* -------------------------------------------------- */
+ /* no rows assembled out of this Uson yet */
+ /* -------------------------------------------------- */
+
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ Row_degree [row]-- ;
+ /* Fcol [Frpos [row]] += C [i] ; */
+ ASSEMBLE (Fcol [Frpos [row]], C [i]) ;
+ }
+ }
+ else
+ {
+ /* -------------------------------------------------- */
+ /* some rows have been assembled out of this Uson */
+ /* -------------------------------------------------- */
+
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0)
+ {
+ ASSERT (row < n_row) ;
+ Row_degree [row]-- ;
+ /* Fcol [Frpos [row]] += C [i] ; */
+ ASSEMBLE (Fcol [Frpos [row]], C [i]) ;
+ }
+ }
+ }
+ ep->ncolsleft-- ;
+ ASSERT (ep->ncolsleft > 0) ;
+ }
+ else
+ {
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ }
+ Col_tlen [col] = tp2 - tp1 ;
+
+#ifndef NDEBUG
+ DEBUG7 (("Column assembled in scan2-col: "ID"\n", col)) ;
+ if (col != Work->pivcol)
+ {
+ UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+ }
+ DEBUG7 (("Current frontal matrix: after scan2-col\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ }
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* done. the remainder of this routine is used only when in debug mode */
+ /* ---------------------------------------------------------------------- */
+
+
+
+#ifndef NDEBUG
+
+ /* ---------------------------------------------------------------------- */
+ /* when debugging: make sure the assembly did everything that it could */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG3 (("::Assemble done\n")) ;
+
+ scan_pivrow = TRUE ;
+
+ for (i2 = 0 ; i2 < fnrows || scan_pivrow ; )
+ {
+ /* Get a row */
+ if (scan_pivrow)
+ {
+ /* pivot row is new to this front. Scan it */
+ row = Work->pivrow ;
+ scan_pivrow = FALSE ;
+ }
+ else
+ {
+ row = Frows [i2++] ;
+ }
+ ASSERT (row >= 0 && row < n_row) ;
+
+ DEBUG6 (("DEBUG SCAN 1: "ID"\n", row)) ;
+ UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ tpi = Row_tuples [row] ;
+ if (!tpi) continue ;
+ tp = (Tuple *) (Memory + tpi) ;
+ tpend = tp + Row_tlen [row] ;
+ 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) ;
+ Rows = ((Int *) p) + ep->ncols ;
+ if (Rows [f] == EMPTY) continue ; /* row already assembled */
+ ASSERT (row == Rows [f]) ;
+ extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
+ extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
+ DEBUG6 ((
+ "e "ID" After assembly ext row deg: "ID" ext col degree "ID"\n",
+ e, extrdeg, extcdeg)) ;
+
+ /* no Lsons in any row */
+ ASSERT (extrdeg > 0) ;
+
+ /* Uson external row degree is = number of cols left */
+ ASSERT (IMPLIES (extcdeg == 0, extrdeg == ep->ncolsleft)) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+
+ scan_pivcol = TRUE ;
+
+ for (j2 = 0 ; j2 < fncols || scan_pivcol ; )
+ {
+ /* Get a column */
+ if (scan_pivcol)
+ {
+ /* pivot col is new to this front. Scan it */
+ col = Work->pivcol ;
+ scan_pivcol = FALSE ;
+ }
+ else
+ {
+ col = Fcols [j2++] ;
+ }
+ ASSERT (col >= 0 && col < n_col) ;
+
+ DEBUG6 (("DEBUG SCAN 2: "ID"\n", col)) ;
+ UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ;
+
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ tpi = Col_tuples [col] ;
+ if (!tpi) continue ;
+ tp = (Tuple *) (Memory + tpi) ;
+ tpend = tp + Col_tlen [col] ;
+ 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 ; /* column already assembled */
+ ASSERT (col == Cols [f]) ;
+ extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
+ extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
+ DEBUG6 (("e "ID" After assembly ext col deg: "ID"\n", e, extcdeg)) ;
+
+ /* no Usons in any column */
+ ASSERT (extcdeg > 0) ;
+
+ /* Lson external column degree is = number of rows left */
+ ASSERT (IMPLIES (extrdeg == 0, extcdeg == ep->nrowsleft)) ;
+ }
+ }
+
+#endif /* NDEBUG */
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_blas3_update.c b/src/sparse-matrix/umfpack/umf_blas3_update.c
new file mode 100644
index 0000000..0deee0e
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_blas3_update.c
@@ -0,0 +1,125 @@
+/* ========================================================================== */
+/* === UMF_blas3_update ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_blas3_update
+(
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Entry *A, *B, *C ;
+ Int k, m, n, d ;
+
+ /* ---------------------------------------------------------------------- */
+ /* perform the matrix-matrix multiply */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG5 (("In UMF_blas3_update "ID" "ID" "ID"\n",
+ Work->fnpiv, Work->fnrows, Work->fncols)) ;
+
+ k = Work->fnpiv ;
+ Work->fnpiv = 0 ; /* no more pivots in frontal working array */
+ Work->fnzeros = 0 ;
+ m = Work->fnrows ;
+ n = Work->fncols ;
+ if (k == 0 || m == 0 || n == 0)
+ {
+ return ;
+ }
+
+ d = Work->fnrows_max ;
+ C = Work->Fx ;
+ A = C + (Work->fncols_max - k) * d ;
+ B = C + d - k ;
+
+ DEBUG5 (("DO RANK-NB UPDATE of frontal:\n")) ;
+ DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* C = C - A*B */
+ /* ---------------------------------------------------------------------- */
+
+ if (k == 1)
+ {
+
+#ifdef USE_NO_BLAS
+
+ /* no BLAS available - use plain C code instead */
+ Int i, j ;
+ Entry b_sj, *c_ij, *a_is ;
+ for (j = 0 ; j < n ; j++)
+ {
+ b_sj = B [j*d] ;
+ if (IS_NONZERO (b_sj))
+ {
+ c_ij = & C [j*d] ;
+ a_is = & A [0] ;
+ for (i = 0 ; i < m ; i++)
+ {
+ /* (*c_ij++) -= b_sj * (*a_is++) ; */
+ MULT_SUB (*c_ij, b_sj, *a_is) ;
+ c_ij++ ;
+ a_is++ ;
+ }
+ }
+ }
+
+#else
+
+ BLAS_GER (m, n, A, B, C, d) ;
+
+#endif /* USE_NO_BLAS */
+
+ }
+ else
+ {
+
+#ifdef USE_NO_BLAS
+
+ /* no BLAS available - use plain C code instead */
+ Int i, j, s ;
+ Entry b_sj, *c_ij, *a_is ;
+ for (j = 0 ; j < n ; j++)
+ {
+ for (s = 0 ; s < k ; s++)
+ {
+ b_sj = B [s+j*d] ;
+ if (IS_NONZERO (b_sj))
+ {
+ c_ij = & C [j*d] ;
+ a_is = & A [s*d] ;
+ for (i = 0 ; i < m ; i++)
+ {
+ /* (*c_ij++) -= b_sj * (*a_is++) ; */
+ MULT_SUB (*c_ij, b_sj, *a_is) ;
+ c_ij++ ;
+ a_is++ ;
+ }
+ }
+ }
+ }
+
+#else
+
+ BLAS_GEMM (m, n, k, A, B, C, d) ;
+
+#endif /* USE_NO_BLAS */
+
+ }
+
+ DEBUG2 (("blas3 "ID" "ID" "ID"\n", k, Work->fnrows, Work->fncols)) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_build_tuples.c b/src/sparse-matrix/umfpack/umf_build_tuples.c
new file mode 100644
index 0000000..c2c4710
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_build_tuples.c
@@ -0,0 +1,158 @@
+/* ========================================================================== */
+/* === UMF_build_tuples ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Construct the tuple lists from a set of packed elements (no holes in
+ elements, no internal or external fragmentation, and a packed (0..Work->nel)
+ element name space). Assume no tuple lists are currently allocated, but
+ that the tuple lengths have been initialized by UMF_tuple_lengths.
+
+ Returns TRUE if successful, FALSE if not enough memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_tail_block.h"
+
+GLOBAL Int UMF_build_tuples
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int e, nrows, ncols, nel, *Rows, *Cols, row, col, n_row, n_col, *E,
+ *Row_tuples, *Row_degree, *Row_tlen, tlen, tsize,
+ *Col_tuples, *Col_degree, *Col_tlen ;
+ Element *ep ;
+ Unit *p ;
+ Tuple tuple, *tp ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ E = Work->E ;
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
+ Row_tuples = Numeric->Uip ;
+ Row_tlen = Numeric->Uilen ;
+ Col_tuples = Numeric->Lip ;
+ Col_tlen = Numeric->Lilen ;
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ nel = Work->nel ;
+
+ DEBUG3 (("BUILD_TUPLES: n_row "ID" n_col "ID" nel "ID"\n",
+ n_row, n_col, nel)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate space for the tuple lists */
+ /* ---------------------------------------------------------------------- */
+
+ /* Garbage collection and memory reallocation have already attempted to */
+ /* ensure that there is enough memory for all the tuple lists. If */
+ /* memory allocation fails here, then there is nothing more to be done. */
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row))
+ {
+ tlen = MAX (4, Row_tlen [row] + 1) ;
+ tsize = UNITS (Tuple, tlen) ;
+ Row_tuples [row] = UMF_mem_alloc_tail_block (Numeric, tsize) ;
+ if (!Row_tuples [row])
+ {
+ return (FALSE) ; /* out of memory for row tuples */
+ }
+ Row_tlen [row] = 0 ;
+ }
+ }
+
+ /* push on stack in reverse order, so column tuples are in the order */
+ /* that they will be deleted. */
+ for (col = n_col-1 ; col >= 0 ; col--)
+ {
+ if (NON_PIVOTAL_COL (col))
+ {
+ tlen = MAX (4, Col_tlen [col] + 1) ;
+ tsize = UNITS (Tuple, tlen) ;
+ Col_tuples [col] = UMF_mem_alloc_tail_block (Numeric, tsize) ;
+ if (!Col_tuples [col])
+ {
+ return (FALSE) ; /* out of memory for col tuples */
+ }
+ Col_tlen [col] = 0 ;
+ }
+ }
+
+#ifndef NDEBUG
+ UMF_dump_memory (Numeric) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* create the tuple lists (exclude element 0) */
+ /* ---------------------------------------------------------------------- */
+
+ /* for all elements, in order of creation */
+ for (e = 1 ; e <= nel ; e++)
+ {
+ DEBUG9 (("Adding tuples for element: "ID" at "ID"\n", e, E [e])) ;
+ ASSERT (E [e]) ; /* no external fragmentation */
+ p = Numeric->Memory + E [e] ;
+ GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncols) ;
+ nrows = ep->nrows ;
+ ASSERT (e != 0) ;
+ ASSERT (e == 0 || nrows == ep->nrowsleft) ;
+ ASSERT (e == 0 || ncols == ep->ncolsleft) ;
+ tuple.e = e ;
+ for (tuple.f = 0 ; tuple.f < ncols ; tuple.f++)
+ {
+ col = Cols [tuple.f] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ ASSERT (Col_tuples [col]) ;
+ tp = ((Tuple *) (Numeric->Memory + Col_tuples [col]))
+ + Col_tlen [col]++ ;
+ *tp = tuple ;
+#ifndef NDEBUG
+ UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+ }
+ for (tuple.f = 0 ; tuple.f < nrows ; tuple.f++)
+ {
+ row = Rows [tuple.f] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ ASSERT (Row_tuples [row]) ;
+ tp = ((Tuple *) (Numeric->Memory + Row_tuples [row]))
+ + Row_tlen [row]++ ;
+ *tp = tuple ;
+#ifndef NDEBUG
+ UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* the tuple lists are now valid, and can be scanned */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ UMF_dump_memory (Numeric) ;
+ UMF_dump_matrix (Numeric, Work, FALSE) ;
+#endif
+ DEBUG3 (("BUILD_TUPLES: done\n")) ;
+ return (TRUE) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_build_tuples_usage.c b/src/sparse-matrix/umfpack/umf_build_tuples_usage.c
new file mode 100644
index 0000000..2f87606
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_build_tuples_usage.c
@@ -0,0 +1,75 @@
+/* ========================================================================== */
+/* === UMF_build_tuples_usage =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Return number of Units needed for UMF_build_tuples */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_build_tuples_usage
+(
+ const Int Col_tlen [ ],
+ const Int Col_degree [ ],
+ const Int Row_tlen [ ],
+ const Int Row_degree [ ],
+ Int n_row,
+ Int n_col,
+ double *dusage /* input and output argument */
+)
+{
+ Int row, col, usage ;
+ double du ;
+
+ /* note: tuple lengths are initialized, but the tuple lists themselves */
+ /* may not be. */
+
+ usage = 0 ;
+ du = 0 ;
+ if (!Col_tlen || !Col_degree)
+ {
+ /* Col_tlen and Col_degree arrays are missing, so this is the */
+ /* initial matrix, with one element per column. */
+ usage += n_col * (1 + UNITS (Tuple, 4)) ;
+ du += ((double) n_col) * (1 + DUNITS (Tuple, 4)) ;
+ }
+ else
+ {
+ for (col = 0 ; col < n_col ; col++)
+ {
+ if (NON_PIVOTAL_COL (col))
+ {
+ usage += 1 + UNITS (Tuple, MAX (4, Col_tlen [col] + 1)) ;
+ du += 1 + DUNITS (Tuple, MAX (4, Col_tlen [col] + 1)) ;
+ }
+ }
+ }
+ ASSERT (Row_tlen && Row_degree) ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row))
+ {
+ usage += 1 + UNITS (Tuple, MAX (4, Row_tlen [row] + 1)) ;
+ du += 1 + DUNITS (Tuple, MAX (4, Row_tlen [row] + 1)) ;
+ }
+ }
+
+ /* roundoff error in du is at most 3*n*epsilon */
+ /* (here, and in UMF_kernel_init_usage) */
+ /* Ignore NaN or Inf behavior here. */
+ du = MAX (du, (double) usage * (1.0 + MAX_EPSILON)) ;
+ du += (((double) n_row) + 2*((double) n_col)) * MAX_EPSILON ;
+ du = ceil (du) ;
+
+ DEBUG0 (("UMF_build_tuples_usage "ID" %g\n", usage, *dusage)) ;
+
+ *dusage += du ;
+ return (usage) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_colamd.c b/src/sparse-matrix/umfpack/umf_colamd.c
new file mode 100644
index 0000000..01b1251
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_colamd.c
@@ -0,0 +1,3077 @@
+/* ========================================================================== */
+/* === UMF_colamd =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+UMF_colamd: an approximate minimum degree column ordering algorithm,
+ used as a preordering for UMFPACK.
+
+Purpose:
+
+ Colamd computes a permutation Q such that the Cholesky factorization of
+ (AQ)'(AQ) has less fill-in and requires fewer floating point operations
+ than A'A. This also provides a good ordering for sparse partial
+ pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+ factorization, and P is computed during numerical factorization via
+ conventional partial pivoting with row interchanges. Colamd is the
+ column ordering method used in SuperLU, part of the ScaLAPACK library.
+ It is also available as built-in function in MATLAB Version 6,
+ available from MathWorks, Inc. (http://www.mathworks.com). This
+ routine can be used in place of colmmd in MATLAB. By default, the \
+ and / operators in MATLAB perform a column ordering (using colmmd
+ or colamd) prior to LU factorization using sparse partial pivoting,
+ in the built-in MATLAB lu(A) routine.
+
+ This code is derived from Colamd Version 2.0.
+
+Authors:
+
+ The authors of the COLAMD code itself are Stefan I. Larimore and Timothy A.
+ Davis, University of Florida. The algorithm was developed in collaboration
+ with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory.
+ The AMD metric on which this is based is by Patrick Amestoy, T. Davis,
+ and Iain Duff.
+
+Date:
+
+ UMFPACK Version: see above.
+ COLAMD Version 2.0 was released on January 31, 2000.
+
+Acknowledgements:
+
+ This work was supported by the National Science Foundation, under
+ grants DMS-9504974 and DMS-9803599.
+
+UMFPACK: Copyright (c) 2002 by Timothy A. Davis. All Rights Reserved.
+
+See the UMFPACK README file for the License for your use of this code.
+
+Availability:
+
+ Both UMFPACK and the original unmodified colamd/symamd library are
+ available at http://www.cise.ufl.edu/research/sparse.
+
+Changes for inclusion in UMFPACK:
+
+ * symamd, symamd_report, and colamd_report removed
+
+ * additional terms added to RowInfo, ColInfo, and stats
+
+ * Frontal matrix information computed for UMFPACK
+
+ * routines renamed
+
+ * column elimination tree post-ordering incorporated. In the original
+ version 2.0, this was performed in colamd.m.
+
+For more information, see:
+
+ Amestoy, P. R. and Davis, T. A. and Duff, I. S.,
+ An approximate minimum degree ordering algorithm,
+ SIAM J. Matrix Analysis and Applic, vol 17, no 4., pp 886-905, 1996.
+
+ Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.,
+ A column approximate minimum degree ordering algorithm,
+ Univ. of Florida, CISE Dept., TR-00-005, Gainesville, FL
+ Oct. 2000. Submitted to ACM Trans. Math. Softw.
+
+*/
+
+/* ========================================================================== */
+/* === Description of user-callable routines ================================ */
+/* ========================================================================== */
+
+/*
+ ----------------------------------------------------------------------------
+ colamd_recommended: removed for UMFPACK
+ ----------------------------------------------------------------------------
+
+ ----------------------------------------------------------------------------
+ colamd_set_defaults:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ colamd_set_defaults (Int knobs [COLAMD_KNOBS]) ;
+
+ Purpose:
+
+ Sets the default parameters. The use of this routine is optional.
+
+ Arguments:
+
+ double knobs [COLAMD_KNOBS] ; Output only.
+
+ Let c = knobs [COLAMD_DENSE_COL], r = knobs [COLAMD_DENSE_ROW].
+ Colamd: rows with more than max (16, r*16*sqrt(n_col))
+ entries are removed prior to ordering. Columns with more than
+ max (16, c*16*sqrt(n_row)) entries are removed prior to
+ ordering, and placed last in the output column ordering.
+
+ Symamd: removed for UMFPACK.
+
+ COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
+ respectively, in colamd.h. Default values of these two knobs
+ are both 0.5. Currently, only knobs [0] and knobs [1] are
+ used, but future versions may use more knobs. If so, they will
+ be properly set to their defaults by the future version of
+ colamd_set_defaults, so that the code that calls colamd will
+ not need to change, assuming that you either use
+ colamd_set_defaults, or pass a (double *) NULL pointer as the
+ knobs array to colamd or symamd.
+
+ ----------------------------------------------------------------------------
+ colamd:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ Int UMF_colamd (Int n_row, Int n_col, Int Alen, Int *A, Int *p,
+ double knobs [COLAMD_KNOBS], Int stats [COLAMD_STATS]) ;
+
+ Purpose:
+
+ Computes a column ordering (Q) of A such that P(AQ)=LU or
+ (AQ)'AQ=LL' have less fill-in and require fewer floating point
+ operations than factorizing the unpermuted matrix A or A'A,
+ respectively.
+
+ Returns:
+
+ TRUE (1) if successful, FALSE (0) otherwise.
+
+ Arguments:
+
+ Int n_row ; Input argument.
+
+ Number of rows in the matrix A.
+ Restriction: n_row >= 0.
+ Colamd returns FALSE if n_row is negative.
+
+ Int n_col ; Input argument.
+
+ Number of columns in the matrix A.
+ Restriction: n_col >= 0.
+ Colamd returns FALSE if n_col is negative.
+
+ Int Alen ; Input argument.
+
+ Restriction (see note):
+ Alen >= 2*nnz + 8*(n_col+1) + 6*(n_row+1) + n_col
+ Colamd returns FALSE if these conditions are not met.
+
+ Note: this restriction makes an modest assumption regarding
+ the size of the two typedef's structures in colamd.h.
+ We do, however, guarantee that
+
+ Alen >= UMF_COLAMD_RECOMMENDED (nnz, n_row, n_col)
+
+ will be sufficient.
+
+ Int A [Alen] ; Input and output argument.
+
+ A is an integer array of size Alen. Alen must be at least as
+ large as the bare minimum value given above, but this is very
+ low, and can result in excessive run time. For best
+ performance, we recommend that Alen be greater than or equal to
+ UMF_COLAMD_RECOMMENDED (nnz, n_row, n_col), which adds
+ nnz/5 to the bare minimum value given above.
+
+ On input, the row indices of the entries in column c of the
+ matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices
+ in a given column c need not be in ascending order, and
+ duplicate row indices may be be present. However, colamd will
+ work a little faster if both of these conditions are met
+ (Colamd puts the matrix into this format, if it finds that the
+ the conditions are not met).
+
+ The matrix is 0-based. That is, rows are in the range 0 to
+ n_row-1, and columns are in the range 0 to n_col-1. Colamd
+ returns FALSE if any row index is out of range.
+
+ A holds the inverse permutation on output.
+
+ Int p [n_col+1] ; Both input and output argument.
+
+ p is an integer array of size n_col+1. On input, it holds the
+ "pointers" for the column form of the matrix A. Column c of
+ the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
+ entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+ for all c in the range 0 to n_col-1. The value p [n_col] is
+ thus the total number of entries in the pattern of the matrix A.
+ Colamd returns FALSE if these conditions are not met.
+
+ On output, if colamd returns TRUE, the array p holds the column
+ permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
+ the first column index in the new ordering, and p [n_col-1] is
+ the last. That is, p [k] = j means that column j of A is the
+ kth pivot column, in AQ, where k is in the range 0 to n_col-1
+ (p [0] = j means that column j of A is the first column in AQ).
+
+ If colamd returns FALSE, then no permutation is returned, and
+ p is undefined on output.
+
+ double knobs [COLAMD_KNOBS] ; Input argument.
+
+ See colamd_set_defaults for a description.
+ The behavior is undefined if knobs contains NaN's.
+ (UMFPACK does not call umf_colamd with NaN-valued knobs).
+
+ Int stats [COLAMD_STATS] ; Output argument.
+
+ Statistics on the ordering, and error status.
+ See colamd.h for related definitions.
+ Colamd returns FALSE if stats is not present.
+
+ stats [0]: number of dense or empty rows ignored.
+
+ stats [1]: number of dense or empty columns ignored (and
+ ordered last in the output permutation p)
+ Note that a row can become "empty" if it
+ contains only "dense" and/or "empty" columns,
+ and similarly a column can become "empty" if it
+ only contains "dense" and/or "empty" rows.
+
+ stats [2]: number of garbage collections performed.
+ This can be excessively high if Alen is close
+ to the minimum required value.
+
+ stats [3]: status code. < 0 is an error code.
+ > 1 is a warning or notice.
+
+ 0 OK. Each column of the input matrix contained
+ row indices in increasing order, with no
+ duplicates.
+
+ -11 Columns of input matrix jumbled
+ (unsorted columns or duplicate entries).
+
+ stats [4]: the bad column index
+ stats [5]: the bad row index
+
+ -1 A is a null pointer
+
+ -2 p is a null pointer
+
+ -3 n_row is negative
+
+ stats [4]: n_row
+
+ -4 n_col is negative
+
+ stats [4]: n_col
+
+ -5 number of nonzeros in matrix is negative
+
+ stats [4]: number of nonzeros, p [n_col]
+
+ -6 p [0] is nonzero
+
+ stats [4]: p [0]
+
+ -7 A is too small
+
+ stats [4]: required size
+ stats [5]: actual size (Alen)
+
+ -8 a column has a zero or negative number of
+ entries (changed for UMFPACK)
+
+ stats [4]: column with <= 0 entries
+ stats [5]: number of entries in col
+
+ -9 a row index is out of bounds
+
+ stats [4]: column with bad row index
+ stats [5]: bad row index
+ stats [6]: n_row, # of rows of matrx
+
+ -10 unused
+
+ -999 (unused; see symamd.c)
+
+ Future versions may return more statistics in the stats array.
+
+ Example:
+
+ See http://www.cise.ufl.edu/~davis/colamd/example.c
+ for a complete example.
+
+ To order the columns of a 5-by-4 matrix with 11 nonzero entries in
+ the following nonzero pattern
+
+ x 0 x 0
+ x 0 x x
+ 0 x x 0
+ 0 0 x x
+ x x 0 0
+
+ with default knobs and no output statistics, do the following:
+
+ #include "colamd.h"
+ #define ALEN UMF_COLAMD_RECOMMENDED (11, 5, 4)
+ Int A [ALEN] = {1, 2, 5, 3, 5, 1, 2, 3, 4, 2, 4} ;
+ Int p [ ] = {0, 3, 5, 9, 11} ;
+ Int stats [COLAMD_STATS] ;
+ UMF_colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
+
+ The permutation is returned in the array p, and A is destroyed.
+
+
+ ----------------------------------------------------------------------------
+ symamd: does not appear in this version for UMFPACK
+ ----------------------------------------------------------------------------
+
+ ----------------------------------------------------------------------------
+ colamd_report: does not appear in this version for UMFPACK
+ ----------------------------------------------------------------------------
+
+ ----------------------------------------------------------------------------
+ symamd_report: does not appear in this version for UMFPACK
+ ----------------------------------------------------------------------------
+
+*/
+
+/* ========================================================================== */
+/* === Scaffolding code definitions ======================================== */
+/* ========================================================================== */
+
+/* ------------------ */
+/* UMFPACK debugging control is in umf_config.h */
+/* ------------------ */
+
+/*
+ Our "scaffolding code" philosophy: In our opinion, well-written library
+ code should keep its "debugging" code, and just normally have it turned off
+ by the compiler so as not to interfere with performance. This serves
+ several purposes:
+
+ (1) assertions act as comments to the reader, telling you what the code
+ expects at that point. All assertions will always be true (unless
+ there really is a bug, of course).
+
+ (2) leaving in the scaffolding code assists anyone who would like to modify
+ the code, or understand the algorithm (by reading the debugging output,
+ one can get a glimpse into what the code is doing).
+
+ (3) (gasp!) for actually finding bugs. This code has been heavily tested
+ and "should" be fully functional and bug-free ... but you never know...
+
+ To enable debugging, comment out the "#define NDEBUG" above. For a MATLAB
+ mexFunction, you will also need to modify mexopts.sh to remove the -DNDEBUG
+ definition. The code will become outrageously slow when debugging is
+ enabled. To control the level of debugging output, set an environment
+ variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging,
+ you should see the following message on the standard output:
+
+ colamd: debug version, D = 1 (THIS WILL BE SLOW!)
+
+ or a similar message for symamd. If you don't, then debugging has not
+ been enabled.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+/* ------------------ */
+/* modified for UMFPACK: */
+#include "umf_internal.h"
+#include "umf_colamd.h"
+#include "umf_order_front_tree.h"
+#include "umf_apply_order.h"
+/* ------------------ */
+
+/* ========================================================================== */
+/* === Definitions ========================================================== */
+/* ========================================================================== */
+
+/* ------------------ */
+/* UMFPACK: duplicate definitions moved to umf_internal.h */
+/* ------------------ */
+
+/* Row and column status */
+#define ALIVE (0)
+#define DEAD (-1)
+
+/* Column status */
+#define DEAD_PRINCIPAL (-1)
+#define DEAD_NON_PRINCIPAL (-2)
+
+/* Macros for row and column status update and checking. */
+#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
+#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
+#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
+#define COL_IS_DEAD(c) (Col [c].start < ALIVE)
+#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
+#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
+#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
+#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
+#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
+
+/* ------------------ */
+/* UMFPACK: Colamd reporting mechanism moved to umf_internal.h */
+/* ------------------ */
+
+/* ========================================================================== */
+/* === Prototypes of PRIVATE routines ======================================= */
+/* ========================================================================== */
+
+PRIVATE Int init_rows_cols
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int p [],
+ Int stats [COLAMD_STATS]
+) ;
+
+PRIVATE void init_scoring
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int head [],
+ double knobs [COLAMD_KNOBS],
+ Int *p_n_row2,
+ Int *p_n_col2,
+ Int *p_max_deg
+ /* ------------------ */
+ /* added for UMFPACK */
+ , Int *p_ndense_row /* number of dense rows */
+ , Int *p_nempty_row /* number of original empty rows */
+ , Int *p_nnewlyempty_row /* number of newly empty rows */
+ , Int *p_ndense_col /* number of dense cols (excl "empty" cols) */
+ , Int *p_nempty_col /* number of original empty cols */
+ , Int *p_nnewlyempty_col /* number of newly empty cols */
+) ;
+
+PRIVATE Int find_ordering
+(
+ Int n_row,
+ Int n_col,
+ Int Alen,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int head [],
+ Int n_col2,
+ Int max_deg,
+ Int pfree
+ /* ------------------ */
+ /* added for UMFPACK: */
+ , Int Front_npivcol [ ]
+ , Int Front_nrows [ ]
+ , Int Front_ncols [ ]
+ , Int Front_parent [ ]
+ , Int Front_cols [ ]
+ , Int *p_nfr
+ /* ------------------ */
+) ;
+
+/* ------------------ */
+/* order_children deleted for UMFPACK: */
+/* ------------------ */
+
+PRIVATE void detect_super_cols
+(
+
+#ifndef NDEBUG
+ Int n_col,
+ Colamd_Row Row [],
+#endif /* NDEBUG */
+
+ Colamd_Col Col [],
+ Int A [],
+ Int head [],
+ Int row_start,
+ Int row_length
+) ;
+
+PRIVATE Int garbage_collection
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int *pfree
+) ;
+
+PRIVATE Int clear_mark
+(
+ Int n_row,
+ Colamd_Row Row []
+) ;
+
+/* ------------------ */
+/* print_report deleted for UMFPACK */
+/* ------------------ */
+
+/* ========================================================================== */
+/* === Debugging prototypes and definitions ================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+/* ------------------ */
+/* debugging macros moved for UMFPACK */
+/* ------------------ */
+
+PRIVATE void debug_deg_lists
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int head [],
+ Int min_score,
+ Int should,
+ Int max_deg
+) ;
+
+PRIVATE void debug_mark
+(
+ Int n_row,
+ Colamd_Row Row [],
+ Int tag_mark,
+ Int max_mark
+) ;
+
+PRIVATE void debug_matrix
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A []
+) ;
+
+PRIVATE void debug_structures
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int n_col2
+) ;
+
+/* ------------------ */
+/* dump_super added for UMFPACK: */
+PRIVATE void dump_super
+(
+ Int super_c,
+ Colamd_Col Col [],
+ Int n_col
+) ;
+/* ------------------ */
+
+#endif /* NDEBUG */
+
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === USER-CALLABLE ROUTINES: ============================================== */
+/* ========================================================================== */
+
+
+/* ========================================================================== */
+/* === colamd_set_defaults ================================================== */
+/* ========================================================================== */
+
+/*
+ The colamd_set_defaults routine sets the default values of the user-
+ controllable parameters for colamd:
+
+ knobs [0] rows with knobs[0]*n_col entries or more are removed
+ prior to ordering in colamd. Rows and columns with
+ knobs[0]*n_col entries or more are removed prior to
+ ordering in symamd and placed last in the output
+ ordering.
+
+ knobs [1] columns with knobs[1]*n_row entries or more are removed
+ prior to ordering in colamd, and placed last in the
+ column permutation. Symamd ignores this knob.
+
+ knobs [2..19] unused, but future versions might use this
+*/
+
+GLOBAL void UMF_colamd_set_defaults
+(
+ /* === Parameters ======================================================= */
+
+ double knobs [COLAMD_KNOBS] /* knob array */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int i ;
+
+ if (!knobs)
+ {
+ return ; /* UMFPACK always passes knobs array */
+ }
+ for (i = 0 ; i < COLAMD_KNOBS ; i++)
+ {
+ knobs [i] = 0 ;
+ }
+ knobs [COLAMD_DENSE_ROW] = 0.2 ; /* default changed for UMFPACK */
+ knobs [COLAMD_DENSE_COL] = 0.2 ; /* default changed for UMFPACK */
+}
+
+
+/* ========================================================================== */
+/* === symamd removed for UMFPACK =========================================== */
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === colamd =============================================================== */
+/* ========================================================================== */
+
+/*
+ The colamd routine computes a column ordering Q of a sparse matrix
+ A such that the LU factorization P(AQ) = LU remains sparse, where P is
+ selected via partial pivoting. The routine can also be viewed as
+ providing a permutation Q such that the Cholesky factorization
+ (AQ)'(AQ) = LL' remains sparse.
+*/
+
+GLOBAL Int UMF_colamd /* returns TRUE if successful, FALSE otherwise*/
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows in A */
+ Int n_col, /* number of columns in A */
+ Int Alen, /* length of A */
+ Int A [], /* row indices of A */
+ Int p [], /* pointers to columns in A */
+ double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
+ Int stats [COLAMD_STATS] /* output statistics and error codes */
+
+ /* ------------------ */
+ /* added for UMFPACK: each Front_ array is of size n_col */
+ , Int Front_npivcol [ ] /* # pivot cols in each front */
+ , Int Front_nrows [ ] /* # of rows in each front (incl. pivot rows) */
+ , Int Front_ncols [ ] /* # of cols in each front (incl. pivot cols) */
+ , Int Front_parent [ ] /* parent of each front */
+ , Int Front_cols [ ] /* link list of pivot columns for each front */
+ , Int *p_nfr /* total number of frontal matrices */
+ /* ------------------ */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int i ; /* loop index */
+ Int nnz ; /* nonzeros in A */
+ Int Row_size ; /* size of Row [], in integers */
+ Int Col_size ; /* size of Col [], in integers */
+ Int need ; /* minimum required length of A */
+ Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */
+ Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */
+ Int n_col2 ; /* number of non-dense, non-empty columns */
+ Int n_row2 ; /* number of non-dense, non-empty rows */
+ Int ngarbage ; /* number of garbage collections performed */
+ Int max_deg ; /* maximum row degree */
+ double default_knobs [COLAMD_KNOBS] ; /* default knobs array */
+
+ /* ------------------ */
+ /* debugging initializations moved for UMFPACK */
+ /* ------------------ */
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Int f, j, nchild, ndense_row, nempty_row, parent,
+ nrows, ncols, frsize, ndense_col, nempty_col, k, col, nfr,
+ *Front_child, *Front_sibling, *Front_maxfr, *Front_order,
+ fprev, maxfrsize, bigf, fnext, bigfprev, *Stack ;
+ Int nnewlyempty_col, nnewlyempty_row ;
+ /* ------------------ */
+
+ /* === Check the input arguments ======================================== */
+
+ if (!stats)
+ {
+ DEBUG0 (("colamd: stats not present\n")) ;
+ return (FALSE) ; /* UMFPACK: always passes stats [ ] */
+ }
+ for (i = 0 ; i < COLAMD_STATS ; i++)
+ {
+ stats [i] = 0 ;
+ }
+ stats [COLAMD_STATUS] = COLAMD_OK ;
+ stats [COLAMD_INFO1] = -1 ;
+ stats [COLAMD_INFO2] = -1 ;
+
+ if (!A) /* A is not present */
+ {
+ /* UMFPACK: always passes A [ ] */
+ DEBUG0 (("colamd: A not present\n")) ;
+ stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+ return (FALSE) ;
+ }
+
+ if (!p) /* p is not present */
+ {
+ /* UMFPACK: always passes p [ ] */
+ DEBUG0 (("colamd: p not present\n")) ;
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+ return (FALSE) ;
+ }
+
+ if (n_row < 0) /* n_row must be >= 0 */
+ {
+ /* UMFPACK: does not call UMF_colamd if n <= 0 */
+ DEBUG0 (("colamd: nrow negative "ID"\n", n_row)) ;
+ stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
+ stats [COLAMD_INFO1] = n_row ;
+ return (FALSE) ;
+ }
+
+ if (n_col < 0) /* n_col must be >= 0 */
+ {
+ /* UMFPACK: does not call UMF_colamd if n <= 0 */
+ DEBUG0 (("colamd: ncol negative "ID"\n", n_col)) ;
+ stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+ stats [COLAMD_INFO1] = n_col ;
+ return (FALSE) ;
+ }
+
+ nnz = p [n_col] ;
+ if (nnz < 0) /* nnz must be >= 0 */
+ {
+ /* UMFPACK: does not call UMF_colamd if nnz < 0 */
+ DEBUG0 (("colamd: number of entries negative "ID"\n", nnz)) ;
+ stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+ stats [COLAMD_INFO1] = nnz ;
+ return (FALSE) ;
+ }
+
+ if (p [0] != 0) /* p [0] must be exactly zero */
+ {
+ DEBUG0 (("colamd: p[0] not zero "ID"\n", p [0])) ;
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+ stats [COLAMD_INFO1] = p [0] ;
+ return (FALSE) ;
+ }
+
+ /* === If no knobs, set default knobs =================================== */
+
+ if (!knobs)
+ {
+ /* UMFPACK: always passes the knobs */
+ UMF_colamd_set_defaults (default_knobs) ;
+ knobs = default_knobs ;
+ }
+
+ /* === Allocate the Row and Col arrays from array A ===================== */
+
+ Col_size = UMF_COLAMD_C (n_col) ;
+ Row_size = UMF_COLAMD_R (n_row) ;
+ need = 2*nnz + n_col + Col_size + Row_size ;
+
+ if (need > Alen)
+ {
+ /* UMFPACK: always passes enough space */
+ /* not enough space in array A to perform the ordering */
+ DEBUG0 (("colamd: Need Alen >= "ID", given only Alen = "ID"\n",
+ need, Alen)) ;
+ stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
+ stats [COLAMD_INFO1] = need ;
+ stats [COLAMD_INFO2] = Alen ;
+ return (FALSE) ;
+ }
+
+ Alen -= Col_size + Row_size ;
+ Col = (Colamd_Col *) &A [Alen] ;
+ Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+ /* === Construct the row and column data structures ===================== */
+
+ if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
+ {
+ /* input matrix is invalid */
+ DEBUG0 (("colamd: Matrix invalid\n")) ;
+ return (FALSE) ;
+ }
+
+ /* === UMFPACK: Initialize front info =================================== */
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ Front_npivcol [col] = 0 ;
+ Front_nrows [col] = 0 ;
+ Front_ncols [col] = 0 ;
+ Front_parent [col] = EMPTY ;
+ Front_cols [col] = EMPTY ;
+ }
+
+ /* === Initialize scores, kill dense rows/columns ======================= */
+
+ init_scoring (n_row, n_col, Row, Col, A, p, knobs,
+ &n_row2, &n_col2, &max_deg
+ /* ------------------ */
+ /* added for UMFPACK: */
+ , &ndense_row, &nempty_row, &nnewlyempty_row
+ , &ndense_col, &nempty_col, &nnewlyempty_col
+ /* ------------------ */
+ ) ;
+ ASSERT (n_row2 == n_row - nempty_row - nnewlyempty_row - ndense_row) ;
+ ASSERT (n_col2 == n_col - nempty_col - nnewlyempty_col - ndense_col) ;
+
+ /* === Order the supercolumns =========================================== */
+
+ ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
+ n_col2, max_deg, 2*nnz
+ /* ------------------ */
+ /* added for UMFPACK: */
+ , Front_npivcol, Front_nrows, Front_ncols, Front_parent, Front_cols
+ , &nfr
+ /* ------------------ */
+ ) ;
+
+ /* ------------------ */
+ /* changed for UMFPACK: */
+
+ /* use A [0..4*nfr-1] as workspace [ [ [ */
+ Front_child = A ;
+ Front_sibling = Front_child + nfr ;
+ Front_maxfr = Front_sibling + nfr ;
+ Front_order = Front_maxfr + nfr ;
+
+ for (j = 0 ; j < nfr ; j++)
+ {
+ Front_child [j] = EMPTY ;
+ Front_sibling [j] = EMPTY ;
+ Front_maxfr [j] = EMPTY ;
+ }
+
+ /* === find maxfr for each front ======================================== */
+
+ DEBUG1 (("\n\n========================================FRONTS:\n")) ;
+ for (j = 0 ; j < nfr ; j++)
+ {
+ parent = Front_parent [j] ;
+ nrows = Front_nrows [j] ;
+ ncols = Front_ncols [j] ;
+ frsize = nrows * ncols ;
+ DEBUG1 ((""ID" : npiv "ID" nrows "ID" ncols "ID" parent "ID" ",
+ j, Front_npivcol [j], nrows, ncols, parent)) ;
+ Front_maxfr [j] = MAX (Front_maxfr [j], frsize) ;
+ DEBUG1 (("Front_maxfr [j = "ID"] = "ID"\n", j, Front_maxfr[j]));
+ if (parent != EMPTY)
+ {
+ /* find the maximum frontsize of self and children */
+ Front_maxfr [parent] = MAX (Front_maxfr [parent], Front_maxfr [j]) ;
+ DEBUG1 (("Front_maxfr [parent = "ID"] = "ID"\n",
+ parent, Front_maxfr [parent])) ;
+ }
+ }
+
+ /* === put the fronts in the child lists ================================ */
+
+ /* try to put them in order of smaller to larger */
+ for (j = nfr-1 ; j >= 0 ; j--)
+ {
+ parent = Front_parent [j] ;
+ if (parent != EMPTY)
+ {
+ /* place the front in the link list of the children its parent */
+ /* bigger fronts will tend to be at the end of the list */
+ Front_sibling [j] = Front_child [parent] ;
+ Front_child [parent] = j ;
+ }
+ }
+
+ /* === Order the front tree via depth-first-search ====================== */
+
+ for (i = 0 ; i < nfr ; i++)
+ {
+ if (Front_child [i] != EMPTY)
+ {
+ DEBUG1 (("Before partial sort, front "ID"\n", i)) ;
+ nchild = 0 ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ DEBUG1 ((" "ID" "ID"\n", f, Front_maxfr [f])) ;
+ nchild++ ;
+ }
+
+ /* find the biggest front in the child list */
+ fprev = EMPTY ;
+ maxfrsize = EMPTY ;
+ bigfprev = EMPTY ;
+ bigf = EMPTY ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ frsize = Front_maxfr [f] ;
+ if (frsize >= maxfrsize)
+ {
+ /* this is the biggest seen so far */
+ maxfrsize = frsize ;
+ bigfprev = fprev ;
+ bigf = f ;
+ }
+ fprev = f ;
+ }
+ ASSERT (bigf != EMPTY) ;
+
+ fnext = Front_sibling [bigf] ;
+
+ DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID" fprev"
+ ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
+
+ if (fnext != EMPTY)
+ {
+ /* if fnext is EMPTY, then bigf is already at the end of list */
+
+ if (bigfprev == EMPTY)
+ {
+ /* delete bigf from the front of the list */
+ Front_child [i] = fnext ;
+ }
+ else
+ {
+ /* delete bigf from the middle of the list */
+ Front_sibling [bigfprev] = fnext ;
+ }
+
+ /* put bigf at the end of the list */
+ Front_sibling [bigf] = EMPTY ;
+ ASSERT (Front_child [i] != EMPTY) ;
+ ASSERT (fprev != bigf) ;
+ ASSERT (fprev != EMPTY) ;
+ Front_sibling [fprev] = bigf ;
+ }
+
+ DEBUG1 (("After partial sort, front "ID"\n", i)) ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ DEBUG1 ((" "ID" "ID"\n", f, Front_maxfr [f])) ;
+ ASSERT (Front_npivcol [f] > 0) ;
+ nchild-- ;
+ }
+ ASSERT (nchild == 0) ;
+ }
+ }
+
+ /* Front_maxfr no longer needed ] */
+
+#ifndef NDEBUG
+ UMF_nbug = nfr ; /* frontal id's are in the range 0..nfr-1 */
+ UMF_fbug = nfr ; /* total number of frontal matrices */
+#endif
+
+ /* use Front_maxfr as workspace for stack */
+ Stack = Front_maxfr ;
+ k = 0 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ if (Front_parent [i] == EMPTY)
+ {
+ DEBUG1 (("Root of front tree "ID"\n", i)) ;
+ k = UMF_order_front_tree (i, k, Front_child, Front_sibling,
+ Front_order, Stack) ;
+ }
+ }
+
+ /* Front_child, Front_sibling no longer needed ] */
+
+ /* use A [0..nfr-1] as workspace */
+ UMF_apply_order (Front_npivcol, Front_order, A, nfr, nfr) ;
+ UMF_apply_order (Front_nrows, Front_order, A, nfr, nfr) ;
+ UMF_apply_order (Front_ncols, Front_order, A, nfr, nfr) ;
+ UMF_apply_order (Front_parent, Front_order, A, nfr, nfr) ;
+ UMF_apply_order (Front_cols, Front_order, A, nfr, nfr) ;
+
+ /* fix the parent to refer to the new numbering */
+ for (i = 0 ; i < nfr ; i++)
+ {
+ parent = Front_parent [i] ;
+ if (parent != EMPTY)
+ {
+ Front_parent [i] = Front_order [parent] ;
+ }
+ }
+
+ /* Front_order longer needed ] */
+
+ /* === Order the columns in the fronts ================================== */
+
+ /* use A [0..n_col-1] as inverse permutation */
+ for (i = 0 ; i < n_col ; i++)
+ {
+ A [i] = -1 ;
+ }
+ k = 0 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ ASSERT (Front_npivcol [i] > 0) ;
+ for (col = Front_cols [i] ; col != EMPTY ; col = Col [col].nextcol)
+ {
+ ASSERT (col >= 0 && col < n_col) ;
+ p [k++] = col ;
+ ASSERT (A [col] == -1) ;
+ A [col] = k ;
+ }
+ }
+
+ /* === Order the "dense" and null columns =============================== */
+
+ ASSERT (k == n_col2) ;
+ if (n_col2 < n_col)
+ {
+ for (col = 0 ; col < n_col ; col++)
+ {
+ if (A [col] == -1)
+ {
+ DEBUG1 (("colamd dense or null col "ID" k: "ID"\n", col, k)) ;
+ k = Col [col].shared2.order ;
+ ASSERT (k >= n_col2 && k < n_col) ;
+ p [k] = col ;
+ A [col] = k ;
+ }
+ }
+ }
+
+ /* ------------------ */
+
+ /* === Return statistics in stats ======================================= */
+
+ /* ------------------ */
+ /* modified for UMFPACK */
+ stats [COLAMD_DENSE_ROW] = ndense_row ;
+ stats [COLAMD_EMPTY_ROW] = nempty_row ;
+ stats [COLAMD_NEWLY_EMPTY_ROW] = nnewlyempty_row ;
+ stats [COLAMD_DENSE_COL] = ndense_col ;
+ stats [COLAMD_EMPTY_COL] = nempty_col ;
+ stats [COLAMD_NEWLY_EMPTY_COL] = nnewlyempty_col ;
+ ASSERT (ndense_col + nempty_col + nnewlyempty_col == n_col - n_col2) ;
+ /* ------------------ */
+ stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
+ *p_nfr = nfr ;
+ DEBUG1 (("colamd: done.\n")) ;
+ return (TRUE) ;
+}
+
+
+
+
+/* ========================================================================== */
+/* === colamd_report removed for UMFPACK ==================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === symamd_report removed for UMFPACK ==================================== */
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === NON-USER-CALLABLE ROUTINES: ========================================== */
+/* ========================================================================== */
+
+/* There are no user-callable routines beyond this point in the file */
+
+
+/* ========================================================================== */
+/* === init_rows_cols ======================================================= */
+/* ========================================================================== */
+
+/*
+ Takes the column form of the matrix in A and creates the row form of the
+ matrix. Also, row and column attributes are stored in the Col and Row
+ structs. If the columns are un-sorted or contain duplicate row indices,
+ this routine will also sort and remove duplicate row indices from the
+ column form of the matrix. Returns FALSE if the matrix is invalid,
+ TRUE otherwise. Not user-callable.
+*/
+
+PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows of A */
+ Int n_col, /* number of columns of A */
+ Colamd_Row Row [], /* of size n_row+1 */
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* row indices of A, of size Alen */
+ Int p [], /* pointers to columns in A, of size n_col+1 */
+ Int stats [COLAMD_STATS] /* colamd statistics */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int col ; /* a column index */
+ Int row ; /* a row index */
+ Int *cp ; /* a column pointer */
+ Int *cp_end ; /* a pointer to the end of a column */
+ /* rp and rp_end not used for UMFPACK */
+ Int last_row ; /* previous row */
+
+ /* === Initialize columns, and check column pointers ==================== */
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ Col [col].start = p [col] ;
+ Col [col].length = p [col+1] - p [col] ;
+
+ if (Col [col].length < 0)
+ {
+ /* column pointers must be non-decreasing */
+ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+ stats [COLAMD_INFO1] = col ;
+ stats [COLAMD_INFO2] = Col [col].length ;
+ DEBUG0 (("colamd: col "ID" length "ID" <= 0\n",
+ col, Col [col].length));
+ return (FALSE) ;
+ }
+
+ Col [col].shared1.thickness = 1 ;
+ Col [col].shared2.score = 0 ;
+ Col [col].shared3.prev = EMPTY ;
+ Col [col].shared4.degree_next = EMPTY ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Col [col].nextcol = EMPTY ;
+ Col [col].lastcol = col ;
+ /* ------------------ */
+ }
+
+ /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
+
+ /* === Scan columns, compute row degrees, and check row indices ========= */
+
+ /* ------------------ */
+ /* stats [COLAMD_INFO3] = 0 ; */
+ /* number of duplicate or unsorted row indices - not computed in UMFPACK */
+ /* ------------------ */
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Row [row].length = 0 ;
+ /* ------------------ */
+ /* removed for UMFPACK */
+ /* Row [row].shared2.mark = -1 ; */
+ /* ------------------ */
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Row [row].thickness = 1 ;
+ Row [row].front = EMPTY ;
+ /* ------------------ */
+ }
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ last_row = -1 ;
+
+ cp = &A [p [col]] ;
+ cp_end = &A [p [col+1]] ;
+
+ while (cp < cp_end)
+ {
+ row = *cp++ ;
+
+ /* make sure row indices within range */
+ if (row < 0 || row >= n_row)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+ stats [COLAMD_INFO1] = col ;
+ stats [COLAMD_INFO2] = row ;
+ /* ------------------ */
+ /* not needed in UMFPACK: */
+ /* stats [COLAMD_INFO3] = n_row ; */
+ /* ------------------ */
+ DEBUG0 (("colamd: row "ID" col "ID" out of bounds\n", row,col));
+ return (FALSE) ;
+ }
+
+ /* ------------------ */
+ /* changed for UMFPACK */
+ if (row <= last_row)
+ {
+ /* row index are unsorted or repeated (or both), thus col */
+ /* is jumbled. This is an error condition for UMFPACK */
+ stats [COLAMD_STATUS] = COLAMD_ERROR_jumbled_matrix ;
+ stats [COLAMD_INFO1] = col ;
+ stats [COLAMD_INFO2] = row ;
+ DEBUG1 (("colamd: row "ID" col "ID" unsorted/duplicate\n",
+ row, col)) ;
+ return (FALSE) ;
+ }
+ /* ------------------ */
+
+ /* ------------------ */
+ /* changed for UMFPACK - jumbled columns not tolerated */
+ Row [row].length++ ;
+ /* ------------------ */
+
+ last_row = row ;
+ }
+ }
+
+ /* === Compute row pointers ============================================= */
+
+ /* row form of the matrix starts directly after the column */
+ /* form of matrix in A */
+ Row [0].start = p [n_col] ;
+ Row [0].shared1.p = Row [0].start ;
+ /* ------------------ */
+ /* removed for UMFPACK */
+ /* Row [0].shared2.mark = -1 ; */
+ /* ------------------ */
+ for (row = 1 ; row < n_row ; row++)
+ {
+ Row [row].start = Row [row-1].start + Row [row-1].length ;
+ Row [row].shared1.p = Row [row].start ;
+ /* ------------------ */
+ /* removed for UMFPACK */
+ /* Row [row].shared2.mark = -1 ; */
+ /* ------------------ */
+ }
+
+ /* === Create row form ================================================== */
+
+ /* ------------------ */
+ /* jumbled matrix case removed for UMFPACK */
+ /* ------------------ */
+
+ ASSERT (stats [COLAMD_STATUS] == COLAMD_OK) ;
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ cp = &A [p [col]] ;
+ cp_end = &A [p [col+1]] ;
+ while (cp < cp_end)
+ {
+ A [(Row [*cp++].shared1.p)++] = col ;
+ }
+ }
+
+ /* === Clear the row marks and set row degrees ========================== */
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Row [row].shared2.mark = 0 ;
+ Row [row].shared1.degree = Row [row].length ;
+ }
+
+ /* ------------------ */
+ /* recreate columns for jumbled matrix case removed for UMFPACK */
+ /* ------------------ */
+
+ return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === init_scoring ========================================================= */
+/* ========================================================================== */
+
+/*
+ Kills dense or empty columns and rows, calculates an initial score for
+ each column, and places all columns in the degree lists. Not user-callable.
+*/
+
+PRIVATE void init_scoring
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows of A */
+ Int n_col, /* number of columns of A */
+ Colamd_Row Row [], /* of size n_row+1 */
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* column form and row form of A */
+ Int head [], /* of size n_col+1 */
+ double knobs [COLAMD_KNOBS],/* parameters */
+ Int *p_n_row2, /* number of non-dense, non-empty rows */
+ Int *p_n_col2, /* number of non-dense, non-empty columns */
+ Int *p_max_deg /* maximum row degree */
+ /* ------------------ */
+ /* added for UMFPACK */
+ , Int *p_ndense_row /* number of dense rows */
+ , Int *p_nempty_row /* number of original empty rows */
+ , Int *p_nnewlyempty_row /* number of newly empty rows */
+ , Int *p_ndense_col /* number of dense cols (excl "empty" cols) */
+ , Int *p_nempty_col /* number of original empty cols */
+ , Int *p_nnewlyempty_col /* number of newly empty cols */
+ /* ------------------ */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int c ; /* a column index */
+ Int r, row ; /* a row index */
+ Int *cp ; /* a column pointer */
+ Int deg ; /* degree of a row or column */
+ Int *cp_end ; /* a pointer to the end of a column */
+ Int *new_cp ; /* new column pointer */
+ Int col_length ; /* length of pruned column */
+ Int score ; /* current column score */
+ Int n_col2 ; /* number of non-dense, non-empty columns */
+ Int n_row2 ; /* number of non-dense, non-empty rows */
+ Int dense_row_count ; /* remove rows with more entries than this */
+ Int dense_col_count ; /* remove cols with more entries than this */
+ Int min_score ; /* smallest column score */
+ Int max_deg ; /* maximum row degree */
+ Int next_col ; /* Used to add to degree list.*/
+
+ /* ------------------ */
+ /* added for UMFPACK */
+ Int ndense_row ; /* number of dense rows */
+ Int nempty_row ; /* number of empty rows */
+ Int nnewlyempty_row ; /* number of newly empty rows */
+ Int ndense_col ; /* number of dense cols (excl "empty" cols) */
+ Int nempty_col ; /* number of original empty cols */
+ Int nnewlyempty_col ; /* number of newly empty cols */
+ Int ne ;
+ /* ------------------ */
+
+#ifndef NDEBUG
+ Int debug_count ; /* debug only. */
+#endif /* NDEBUG */
+
+ /* === Extract knobs ==================================================== */
+
+ /* --------------------- */
+ /* old dense row/column knobs:
+ dense_row_count = MAX (0, MIN (knobs [COLAMD_DENSE_ROW] * n_col, n_col)) ;
+ dense_col_count = MAX (0, MIN (knobs [COLAMD_DENSE_COL] * n_row, n_row)) ;
+ */
+ /* new, for UMFPACK: */
+ /* Note: if knobs contains a NaN, this is undefined: */
+ dense_row_count =
+ UMFPACK_DENSE_DEGREE_THRESHOLD (knobs [COLAMD_DENSE_ROW], n_col) ;
+ dense_col_count =
+ UMFPACK_DENSE_DEGREE_THRESHOLD (knobs [COLAMD_DENSE_COL], n_row) ;
+ /* Make sure dense_*_count is between 0 and n: */
+ dense_row_count = MAX (0, MIN (dense_row_count, n_col)) ;
+ dense_col_count = MAX (0, MIN (dense_col_count, n_row)) ;
+ /* --------------------- */
+
+ DEBUG1 (("colamd: densecount: "ID" "ID"\n",
+ dense_row_count, dense_col_count)) ;
+ max_deg = 0 ;
+ n_col2 = n_col ;
+ n_row2 = n_row ;
+
+ /* --------------------- */
+ /* added for UMFPACK */
+ ndense_col = 0 ;
+ nempty_col = 0 ;
+ nnewlyempty_col = 0 ;
+ ndense_row = 0 ;
+ nempty_row = 0 ;
+ nnewlyempty_row = 0 ;
+ /* --------------------- */
+
+ /* === Kill empty columns =============================================== */
+
+ /* Put the empty columns at the end in their natural order, so that LU */
+ /* factorization can proceed as far as possible. */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ deg = Col [c].length ;
+ if (deg == 0)
+ {
+ /* this is a empty column, kill and order it last */
+ Col [c].shared2.order = --n_col2 ;
+ KILL_PRINCIPAL_COL (c) ;
+ /* --------------------- */
+ /* added for UMFPACK */
+ nempty_col++ ;
+ /* --------------------- */
+ }
+ }
+ DEBUG1 (("colamd: null columns killed: "ID"\n", n_col - n_col2)) ;
+
+ /* === Count null rows ================================================== */
+
+ for (r = 0 ; r < n_row ; r++)
+ {
+ deg = Row [r].shared1.degree ;
+ if (deg == 0)
+ {
+ /* this is an original empty row */
+ nempty_row++ ;
+ }
+ }
+
+ /* === Kill dense columns =============================================== */
+
+ /* Put the dense columns at the end, in their natural order */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ /* skip any dead columns */
+ if (COL_IS_DEAD (c))
+ {
+ continue ;
+ }
+ deg = Col [c].length ;
+ if (deg > dense_col_count)
+ {
+ /* this is a dense column, kill and order it last */
+ Col [c].shared2.order = --n_col2 ;
+ /* --------------------- */
+ /* added for UMFPACK */
+ ndense_col++ ;
+ /* --------------------- */
+ /* decrement the row degrees */
+ cp = &A [Col [c].start] ;
+ cp_end = cp + Col [c].length ;
+ while (cp < cp_end)
+ {
+ Row [*cp++].shared1.degree-- ;
+ }
+ KILL_PRINCIPAL_COL (c) ;
+ }
+ }
+ DEBUG1 (("colamd: Dense and null columns killed: "ID"\n", n_col - n_col2)) ;
+
+ /* === Kill dense and empty rows ======================================== */
+
+ ne = 0 ;
+ for (r = 0 ; r < n_row ; r++)
+ {
+ deg = Row [r].shared1.degree ;
+ ASSERT (deg >= 0 && deg <= n_col) ;
+ /* --------------------- */
+ /* added for UMFPACK */
+ if (deg > dense_row_count)
+ {
+ /* There is at least one dense row. Continue ordering, but */
+ /* symbolic factorization will be redone after UMF_colamd is done.*/
+ ndense_row++ ;
+ }
+ if (deg == 0)
+ {
+ /* this is a newly empty row, or original empty row */
+ ne++ ;
+ }
+ /* --------------------- */
+ if (deg > dense_row_count || deg == 0)
+ {
+ /* kill a dense or empty row */
+ KILL_ROW (r) ;
+ /* --------------------- */
+ /* added for UMFPACK */
+ Row [r].thickness = 0 ;
+ /* --------------------- */
+ --n_row2 ;
+ }
+ else
+ {
+ /* keep track of max degree of remaining rows */
+ max_deg = MAX (max_deg, deg) ;
+ }
+ }
+ nnewlyempty_row = ne - nempty_row ;
+ DEBUG1 (("colamd: Dense rows killed: "ID"\n", ndense_row)) ;
+ DEBUG1 (("colamd: Dense and null rows killed: "ID"\n", n_row - n_row2)) ;
+
+ /* === Compute initial column scores ==================================== */
+
+ /* At this point the row degrees are accurate. They reflect the number */
+ /* of "live" (non-dense) columns in each row. No empty rows exist. */
+ /* Some "live" columns may contain only dead rows, however. These are */
+ /* pruned in the code below. */
+
+ /* now find the initial matlab score for each column */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ /* skip dead column */
+ if (COL_IS_DEAD (c))
+ {
+ continue ;
+ }
+ score = 0 ;
+ cp = &A [Col [c].start] ;
+ new_cp = cp ;
+ cp_end = cp + Col [c].length ;
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ /* skip if dead */
+ if (ROW_IS_DEAD (row))
+ {
+ continue ;
+ }
+ /* compact the column */
+ *new_cp++ = row ;
+ /* add row's external degree */
+ score += Row [row].shared1.degree - 1 ;
+ /* guard against integer overflow */
+ score = MIN (score, n_col) ;
+ }
+ /* determine pruned column length */
+ col_length = (Int) (new_cp - &A [Col [c].start]) ;
+ if (col_length == 0)
+ {
+ /* a newly-made null column (all rows in this col are "dense" */
+ /* and have already been killed) */
+ DEBUG2 (("Newly null killed: "ID"\n", c)) ;
+ Col [c].shared2.order = --n_col2 ;
+ KILL_PRINCIPAL_COL (c) ;
+ /* --------------------- */
+ /* added for UMFPACK */
+ nnewlyempty_col++ ;
+ /* --------------------- */
+ }
+ else
+ {
+ /* set column length and set score */
+ ASSERT (score >= 0) ;
+ ASSERT (score <= n_col) ;
+ Col [c].length = col_length ;
+ Col [c].shared2.score = score ;
+ }
+ }
+ DEBUG1 (("colamd: Dense, null, and newly-null columns killed: "ID"\n",
+ n_col-n_col2)) ;
+
+ /* At this point, all empty rows and columns are dead. All live columns */
+ /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
+ /* yet). Rows may contain dead columns, but all live rows contain at */
+ /* least one live column. */
+
+#ifndef NDEBUG
+ debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
+#endif /* NDEBUG */
+
+ /* === Initialize degree lists ========================================== */
+
+#ifndef NDEBUG
+ debug_count = 0 ;
+#endif /* NDEBUG */
+
+ /* clear the hash buckets */
+ for (c = 0 ; c <= n_col ; c++)
+ {
+ head [c] = EMPTY ;
+ }
+ min_score = n_col ;
+ /* place in reverse order, so low column indices are at the front */
+ /* of the lists. This is to encourage natural tie-breaking */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ /* only add principal columns to degree lists */
+ if (COL_IS_ALIVE (c))
+ {
+ DEBUG4 (("place "ID" score "ID" minscore "ID" ncol "ID"\n",
+ c, Col [c].shared2.score, min_score, n_col)) ;
+
+ /* === Add columns score to DList =============================== */
+
+ score = Col [c].shared2.score ;
+
+ ASSERT (min_score >= 0) ;
+ ASSERT (min_score <= n_col) ;
+ ASSERT (score >= 0) ;
+ ASSERT (score <= n_col) ;
+ ASSERT (head [score] >= EMPTY) ;
+
+ /* now add this column to dList at proper score location */
+ next_col = head [score] ;
+ Col [c].shared3.prev = EMPTY ;
+ Col [c].shared4.degree_next = next_col ;
+
+ /* if there already was a column with the same score, set its */
+ /* previous pointer to this new column */
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = c ;
+ }
+ head [score] = c ;
+
+ /* see if this score is less than current min */
+ min_score = MIN (min_score, score) ;
+
+#ifndef NDEBUG
+ debug_count++ ;
+#endif /* NDEBUG */
+
+ }
+ }
+
+#ifndef NDEBUG
+ DEBUG1 (("colamd: Live cols "ID" out of "ID", non-princ: "ID"\n",
+ debug_count, n_col, n_col-debug_count)) ;
+ ASSERT (debug_count == n_col2) ;
+ debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
+#endif /* NDEBUG */
+
+ /* === Return number of remaining columns, and max row degree =========== */
+
+ *p_n_col2 = n_col2 ;
+ *p_n_row2 = n_row2 ;
+ *p_max_deg = max_deg ;
+
+ /* --------------------- */
+ /* added for UMFPACK */
+ *p_ndense_row = ndense_row ;
+ *p_nempty_row = nempty_row ; /* original empty rows */
+ *p_nnewlyempty_row = nnewlyempty_row ;
+ *p_ndense_col = ndense_col ;
+ *p_nempty_col = nempty_col ; /* original empty cols */
+ *p_nnewlyempty_col = nnewlyempty_col ;
+ /* --------------------- */
+}
+
+
+/* ========================================================================== */
+/* === find_ordering ======================================================== */
+/* ========================================================================== */
+
+/*
+ Order the principal columns of the supercolumn form of the matrix
+ (no supercolumns on input). Uses a minimum approximate column minimum
+ degree ordering method. Not user-callable.
+*/
+
+PRIVATE Int find_ordering /* return the number of garbage collections */
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows of A */
+ Int n_col, /* number of columns of A */
+ Int Alen, /* size of A, 2*nnz + n_col or larger */
+ Colamd_Row Row [], /* of size n_row+1 */
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* column form and row form of A */
+ Int head [], /* of size n_col+1 */
+ Int n_col2, /* Remaining columns to order */
+ Int max_deg, /* Maximum row degree */
+ Int pfree /* index of first free slot (2*nnz on entry) */
+ /* ------------------ */
+ /* added for UMFPACK: */
+ , Int Front_npivcol [ ]
+ , Int Front_nrows [ ]
+ , Int Front_ncols [ ]
+ , Int Front_parent [ ]
+ , Int Front_cols [ ]
+ , Int *p_nfr /* number of fronts */
+ /* ------------------ */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int k ; /* current pivot ordering step */
+ Int pivot_col ; /* current pivot column */
+ Int *cp ; /* a column pointer */
+ Int *rp ; /* a row pointer */
+ Int pivot_row ; /* current pivot row */
+ Int *new_cp ; /* modified column pointer */
+ Int *new_rp ; /* modified row pointer */
+ Int pivot_row_start ; /* pointer to start of pivot row */
+ Int pivot_row_degree ; /* number of columns in pivot row */
+ Int pivot_row_length ; /* number of supercolumns in pivot row */
+ Int pivot_col_score ; /* score of pivot column */
+ Int needed_memory ; /* free space needed for pivot row */
+ Int *cp_end ; /* pointer to the end of a column */
+ Int *rp_end ; /* pointer to the end of a row */
+ Int row ; /* a row index */
+ Int col ; /* a column index */
+ Int max_score ; /* maximum possible score */
+ Int cur_score ; /* score of current column */
+ unsigned Int hash ; /* hash value for supernode detection */
+ Int head_column ; /* head of hash bucket */
+ Int first_col ; /* first column in hash bucket */
+ Int tag_mark ; /* marker value for mark array */
+ Int row_mark ; /* Row [row].shared2.mark */
+ Int set_difference ; /* set difference size of row with pivot row */
+ Int min_score ; /* smallest column score */
+ Int col_thickness ; /* "thickness" (no. of columns in a supercol) */
+ Int max_mark ; /* maximum value of tag_mark */
+ Int pivot_col_thickness ; /* number of columns represented by pivot col */
+ Int prev_col ; /* Used by Dlist operations. */
+ Int next_col ; /* Used by Dlist operations. */
+ Int ngarbage ; /* number of garbage collections performed */
+
+#ifndef NDEBUG
+ Int debug_d ; /* debug loop counter */
+ Int debug_step = 0 ; /* debug loop counter */
+#endif /* NDEBUG */
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Int pivot_row_thickness ; /* number of rows represented by pivot row */
+ Int nfr = 0 ; /* number of fronts */
+ Int child ;
+ /* ------------------ */
+
+ /* === Initialization and clear mark ==================================== */
+
+ max_mark = MAX_MARK (n_col) ; /* defined in umfpack.h */
+ tag_mark = clear_mark (n_row, Row) ;
+ min_score = 0 ;
+ ngarbage = 0 ;
+ DEBUG1 (("colamd: Ordering, n_col2="ID"\n", n_col2)) ;
+
+ /* === Order the columns ================================================ */
+
+ for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
+ {
+
+#ifndef NDEBUG
+ if (debug_step % 100 == 0)
+ {
+ DEBUG2 (("\n... Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ;
+ }
+ else
+ {
+ DEBUG3 (("\n-----Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ;
+ }
+ debug_step++ ;
+ debug_deg_lists (n_row, n_col, Row, Col, head,
+ min_score, n_col2-k, max_deg) ;
+ debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+
+ /* === Select pivot column, and order it ============================ */
+
+ /* make sure degree list isn't empty */
+ ASSERT (min_score >= 0) ;
+ ASSERT (min_score <= n_col) ;
+ ASSERT (head [min_score] >= EMPTY) ;
+
+#ifndef NDEBUG
+ for (debug_d = 0 ; debug_d < min_score ; debug_d++)
+ {
+ ASSERT (head [debug_d] == EMPTY) ;
+ }
+#endif /* NDEBUG */
+
+ /* get pivot column from head of minimum degree list */
+ while (head [min_score] == EMPTY && min_score < n_col)
+ {
+ min_score++ ;
+ }
+ pivot_col = head [min_score] ;
+ ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
+ next_col = Col [pivot_col].shared4.degree_next ;
+ head [min_score] = next_col ;
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = EMPTY ;
+ }
+
+ ASSERT (COL_IS_ALIVE (pivot_col)) ;
+ DEBUG3 (("Pivot col: "ID"\n", pivot_col)) ;
+
+ /* remember score for defrag check */
+ pivot_col_score = Col [pivot_col].shared2.score ;
+
+ /* the pivot column is the kth column in the pivot order */
+ Col [pivot_col].shared2.order = k ;
+
+ /* increment order count by column thickness */
+ pivot_col_thickness = Col [pivot_col].shared1.thickness ;
+ /* ------------------ */
+ /* changed for UMFPACK: */
+ k += pivot_col_thickness ;
+ /* ------------------ */
+ ASSERT (pivot_col_thickness > 0) ;
+
+ /* === Garbage_collection, if necessary ============================= */
+
+ needed_memory = MIN (pivot_col_score, n_col - k) ;
+ if (pfree + needed_memory >= Alen)
+ {
+ pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
+ ngarbage++ ;
+ /* after garbage collection we will have enough */
+ ASSERT (pfree + needed_memory < Alen) ;
+ /* garbage collection has wiped out the Row[].shared2.mark array */
+ tag_mark = clear_mark (n_row, Row) ;
+
+#ifndef NDEBUG
+ debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+ }
+
+ /* === Compute pivot row pattern ==================================== */
+
+ /* get starting location for this new merged row */
+ pivot_row_start = pfree ;
+
+ /* initialize new row counts to zero */
+ pivot_row_degree = 0 ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ pivot_row_thickness = 0 ;
+ /* ------------------ */
+
+ /* [ tag pivot column as having been visited so it isn't included */
+ /* in merged pivot row */
+ Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
+
+ /* pivot row is the union of all rows in the pivot column pattern */
+ cp = &A [Col [pivot_col].start] ;
+ cp_end = cp + Col [pivot_col].length ;
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ DEBUG4 (("Pivot col pattern "ID" "ID"\n", ROW_IS_ALIVE(row), row)) ;
+ /* skip if row is dead */
+ if (ROW_IS_DEAD (row))
+ {
+ continue ;
+ }
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ /* sum the thicknesses of all the rows */
+ ASSERT (Row [row].thickness > 0) ;
+ pivot_row_thickness += Row [row].thickness ;
+ /* ------------------ */
+
+ rp = &A [Row [row].start] ;
+ rp_end = rp + Row [row].length ;
+ while (rp < rp_end)
+ {
+ /* get a column */
+ col = *rp++ ;
+ /* add the column, if alive and untagged */
+ col_thickness = Col [col].shared1.thickness ;
+ if (col_thickness > 0 && COL_IS_ALIVE (col))
+ {
+ /* tag column in pivot row */
+ Col [col].shared1.thickness = -col_thickness ;
+ ASSERT (pfree < Alen) ;
+ /* place column in pivot row */
+ A [pfree++] = col ;
+ pivot_row_degree += col_thickness ;
+ /* ------------------ */
+ /* added for UMFPACK: */
+ DEBUG4 (("\t\t\tNew live column in pivot row: "ID"\n",col));
+ /* ------------------ */
+ }
+/* ------------------ */
+/* added for UMFPACK */
+#ifndef NDEBUG
+ if (col_thickness < 0 && COL_IS_ALIVE (col))
+ {
+ DEBUG4 (("\t\t\tOld live column in pivot row: "ID"\n",col));
+ }
+#endif
+/* ------------------ */
+ }
+ }
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ /* pivot_row_thickness is the number of rows in frontal matrix */
+ /* both pivotal rows and nonpivotal rows */
+ /* ------------------ */
+
+ /* clear tag on pivot column */
+ Col [pivot_col].shared1.thickness = pivot_col_thickness ; /* ] */
+ max_deg = MAX (max_deg, pivot_row_degree) ;
+
+#ifndef NDEBUG
+ DEBUG3 (("check2\n")) ;
+ debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+ /* === Kill all rows used to construct pivot row ==================== */
+
+ /* also kill pivot row, temporarily */
+ cp = &A [Col [pivot_col].start] ;
+ cp_end = cp + Col [pivot_col].length ;
+ while (cp < cp_end)
+ {
+ /* may be killing an already dead row */
+ row = *cp++ ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ DEBUG2 (("Kill row in pivot col: "ID" alive? "ID", front "ID"\n",
+ row, ROW_IS_ALIVE (row), Row [row].front)) ;
+
+ if (ROW_IS_ALIVE (row) && Row [row].front != EMPTY)
+ {
+ /* Row [row].front is a child of current front */
+ child = Row [row].front ;
+ Front_parent [child] = nfr ;
+ }
+ /* ------------------ */
+
+ KILL_ROW (row) ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Row [row].thickness = 0 ;
+ /* ------------------ */
+ }
+
+ /* === Select a row index to use as the new pivot row =============== */
+
+ pivot_row_length = pfree - pivot_row_start ;
+ if (pivot_row_length > 0)
+ {
+ /* pick the "pivot" row arbitrarily (first row in col) */
+ pivot_row = A [Col [pivot_col].start] ;
+ DEBUG3 (("Pivotal row is "ID"\n", pivot_row)) ;
+ }
+ else
+ {
+ /* there is no pivot row, since it is of zero length */
+ pivot_row = EMPTY ;
+ ASSERT (pivot_row_length == 0) ;
+ }
+ ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
+
+ /* === Approximate degree computation =============================== */
+
+ /* Here begins the computation of the approximate degree. The column */
+ /* score is the sum of the pivot row "length", plus the size of the */
+ /* set differences of each row in the column minus the pattern of the */
+ /* pivot row itself. The column ("thickness") itself is also */
+ /* excluded from the column score (we thus use an approximate */
+ /* external degree). */
+
+ /* The time taken by the following code (compute set differences, and */
+ /* add them up) is proportional to the size of the data structure */
+ /* being scanned - that is, the sum of the sizes of each column in */
+ /* the pivot row. Thus, the amortized time to compute a column score */
+ /* is proportional to the size of that column (where size, in this */
+ /* context, is the column "length", or the number of row indices */
+ /* in that column). The number of row indices in a column is */
+ /* monotonically non-decreasing, from the length of the original */
+ /* column on input to colamd. */
+
+ /* === Compute set differences ====================================== */
+
+ DEBUG3 (("** Computing set differences phase. **\n")) ;
+
+ /* pivot row is currently dead - it will be revived later. */
+
+ DEBUG3 (("Pivot row: \n")) ;
+ /* for each column in pivot row */
+ rp = &A [pivot_row_start] ;
+ rp_end = rp + pivot_row_length ;
+ while (rp < rp_end)
+ {
+ col = *rp++ ;
+ ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+ DEBUG3 ((" Col: "ID"\n", col)) ;
+
+ /* clear tags used to construct pivot row pattern */
+ col_thickness = -Col [col].shared1.thickness ;
+ ASSERT (col_thickness > 0) ;
+ Col [col].shared1.thickness = col_thickness ;
+
+ /* === Remove column from degree list =========================== */
+
+ cur_score = Col [col].shared2.score ;
+ prev_col = Col [col].shared3.prev ;
+ next_col = Col [col].shared4.degree_next ;
+ ASSERT (cur_score >= 0) ;
+ ASSERT (cur_score <= n_col) ;
+ ASSERT (cur_score >= EMPTY) ;
+ if (prev_col == EMPTY)
+ {
+ head [cur_score] = next_col ;
+ }
+ else
+ {
+ Col [prev_col].shared4.degree_next = next_col ;
+ }
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = prev_col ;
+ }
+
+ /* === Scan the column ========================================== */
+
+ cp = &A [Col [col].start] ;
+ cp_end = cp + Col [col].length ;
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ row_mark = Row [row].shared2.mark ;
+ /* skip if dead */
+ if (ROW_IS_MARKED_DEAD (row_mark))
+ {
+ continue ;
+ }
+ ASSERT (row != pivot_row) ;
+ set_difference = row_mark - tag_mark ;
+ /* check if the row has been seen yet */
+ if (set_difference < 0)
+ {
+ ASSERT (Row [row].shared1.degree <= max_deg) ;
+ set_difference = Row [row].shared1.degree ;
+ }
+ /* subtract column thickness from this row's set difference */
+ set_difference -= col_thickness ;
+ ASSERT (set_difference >= 0) ;
+
+ /* ------------------ */
+ /* aggressive row absorption removed for UMFPACK */
+ /* ------------------ */
+
+ /* save the new mark */
+ Row [row].shared2.mark = set_difference + tag_mark ;
+
+ }
+ }
+
+#ifndef NDEBUG
+ debug_deg_lists (n_row, n_col, Row, Col, head,
+ min_score, n_col2-k-pivot_row_degree, max_deg) ;
+#endif /* NDEBUG */
+
+ /* === Add up set differences for each column ======================= */
+
+ DEBUG3 (("** Adding set differences phase. **\n")) ;
+
+ /* for each column in pivot row */
+ rp = &A [pivot_row_start] ;
+ rp_end = rp + pivot_row_length ;
+ while (rp < rp_end)
+ {
+ /* get a column */
+ col = *rp++ ;
+ ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+ hash = 0 ;
+ cur_score = 0 ;
+ cp = &A [Col [col].start] ;
+ /* compact the column */
+ new_cp = cp ;
+ cp_end = cp + Col [col].length ;
+
+ DEBUG4 (("Adding set diffs for Col: "ID".\n", col)) ;
+
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ ASSERT(row >= 0 && row < n_row) ;
+ row_mark = Row [row].shared2.mark ;
+ /* skip if dead */
+ if (ROW_IS_MARKED_DEAD (row_mark))
+ {
+ /* ------------------ */
+ /* changed for UMFPACK: */
+ DEBUG4 ((" Row "ID", dead\n", row)) ;
+ /* ------------------ */
+ continue ;
+ }
+ /* ------------------ */
+ /* changed for UMFPACK: */
+ /* ASSERT (row_mark > tag_mark) ; */
+ DEBUG4 ((" Row "ID", set diff "ID"\n", row, row_mark-tag_mark));
+ ASSERT (row_mark >= tag_mark) ;
+ /* ------------------ */
+ /* compact the column */
+ *new_cp++ = row ;
+ /* compute hash function */
+ hash += row ;
+ /* add set difference */
+ cur_score += row_mark - tag_mark ;
+ /* integer overflow... */
+ cur_score = MIN (cur_score, n_col) ;
+ }
+
+ /* recompute the column's length */
+ Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
+
+ /* === Further mass elimination ================================= */
+
+ if (Col [col].length == 0)
+ {
+ DEBUG4 (("further mass elimination. Col: "ID"\n", col)) ;
+ /* nothing left but the pivot row in this column */
+ KILL_PRINCIPAL_COL (col) ;
+ pivot_row_degree -= Col [col].shared1.thickness ;
+ ASSERT (pivot_row_degree >= 0) ;
+ /* order it */
+ Col [col].shared2.order = k ;
+ /* increment order count by column thickness */
+ k += Col [col].shared1.thickness ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ pivot_col_thickness += Col [col].shared1.thickness ;
+
+ /* add to column list of front ... */
+#ifndef NDEBUG
+ DEBUG1 (("Mass")) ;
+ dump_super (col, Col, n_col) ;
+#endif
+ Col [Col [col].lastcol].nextcol = Front_cols [nfr] ;
+ Front_cols [nfr] = col ;
+ /* ------------------ */
+
+ }
+ else
+ {
+ /* === Prepare for supercolumn detection ==================== */
+
+ DEBUG4 (("Preparing supercol detection for Col: "ID".\n", col));
+
+ /* save score so far */
+ Col [col].shared2.score = cur_score ;
+
+ /* add column to hash table, for supercolumn detection */
+ hash %= n_col + 1 ;
+
+ DEBUG4 ((" Hash = "ID", n_col = "ID".\n", hash, n_col)) ;
+ ASSERT (hash <= n_col) ;
+
+ head_column = head [hash] ;
+ if (head_column > EMPTY)
+ {
+ /* degree list "hash" is non-empty, use prev (shared3) of */
+ /* first column in degree list as head of hash bucket */
+ first_col = Col [head_column].shared3.headhash ;
+ Col [head_column].shared3.headhash = col ;
+ }
+ else
+ {
+ /* degree list "hash" is empty, use head as hash bucket */
+ first_col = - (head_column + 2) ;
+ head [hash] = - (col + 2) ;
+ }
+ Col [col].shared4.hash_next = first_col ;
+
+ /* save hash function in Col [col].shared3.hash */
+ Col [col].shared3.hash = (Int) hash ;
+ ASSERT (COL_IS_ALIVE (col)) ;
+ }
+ }
+
+ /* The approximate external column degree is now computed. */
+
+ /* === Supercolumn detection ======================================== */
+
+ DEBUG3 (("** Supercolumn detection phase. **\n")) ;
+
+ detect_super_cols (
+
+#ifndef NDEBUG
+ n_col, Row,
+#endif /* NDEBUG */
+
+ Col, A, head, pivot_row_start, pivot_row_length) ;
+
+ /* === Kill the pivotal column ====================================== */
+
+ KILL_PRINCIPAL_COL (pivot_col) ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ /* add columns to column list of front */
+#ifndef NDEBUG
+ DEBUG1 (("Pivot")) ;
+ dump_super (pivot_col, Col, n_col) ;
+#endif
+ Col [Col [pivot_col].lastcol].nextcol = Front_cols [nfr] ;
+ Front_cols [nfr] = pivot_col ;
+ /* ------------------ */
+
+ /* === Clear mark =================================================== */
+
+ tag_mark += (max_deg + 1) ;
+ if (tag_mark >= max_mark)
+ {
+ DEBUG2 (("clearing tag_mark\n")) ;
+ tag_mark = clear_mark (n_row, Row) ;
+ }
+
+#ifndef NDEBUG
+ DEBUG3 (("check3\n")) ;
+ debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+ /* === Finalize the new pivot row, and column scores ================ */
+
+ DEBUG3 (("** Finalize scores phase. **\n")) ;
+ DEBUG3 (("pivot_row_degree "ID"\n", pivot_row_degree)) ;
+
+ /* for each column in pivot row */
+ rp = &A [pivot_row_start] ;
+ /* compact the pivot row */
+ new_rp = rp ;
+ rp_end = rp + pivot_row_length ;
+ while (rp < rp_end)
+ {
+ col = *rp++ ;
+ DEBUG3 (("Col "ID" \n", col)) ;
+ /* skip dead columns */
+ if (COL_IS_DEAD (col))
+ {
+ DEBUG3 (("dead\n")) ;
+ continue ;
+ }
+ *new_rp++ = col ;
+ /* add new pivot row to column */
+ A [Col [col].start + (Col [col].length++)] = pivot_row ;
+
+ /* retrieve score so far and add on pivot row's degree. */
+ /* (we wait until here for this in case the pivot */
+ /* row's degree was reduced due to mass elimination). */
+ DEBUG3 ((" cur_score "ID" ", cur_score)) ;
+ cur_score = Col [col].shared2.score + pivot_row_degree ;
+ DEBUG3 (("ID", cur_score)) ;
+
+ /* calculate the max possible score as the number of */
+ /* external columns minus the 'k' value minus the */
+ /* columns thickness */
+ max_score = n_col - k - Col [col].shared1.thickness ;
+ DEBUG3 ((" max_score "ID" ", max_score)) ;
+
+ /* make the score the external degree of the union-of-rows */
+ cur_score -= Col [col].shared1.thickness ;
+ DEBUG3 ((" cur_score "ID" ", cur_score)) ;
+
+ /* make sure score is less or equal than the max score */
+ cur_score = MIN (cur_score, max_score) ;
+ ASSERT (cur_score >= 0) ;
+
+ /* store updated score */
+ Col [col].shared2.score = cur_score ;
+ DEBUG3 ((" "ID"\n", cur_score)) ;
+
+ /* === Place column back in degree list ========================= */
+
+ ASSERT (min_score >= 0) ;
+ ASSERT (min_score <= n_col) ;
+ ASSERT (cur_score >= 0) ;
+ ASSERT (cur_score <= n_col) ;
+ ASSERT (head [cur_score] >= EMPTY) ;
+ next_col = head [cur_score] ;
+ Col [col].shared4.degree_next = next_col ;
+ Col [col].shared3.prev = EMPTY ;
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = col ;
+ }
+ head [cur_score] = col ;
+
+ /* see if this score is less than current min */
+ min_score = MIN (min_score, cur_score) ;
+
+ }
+
+#ifndef NDEBUG
+ debug_deg_lists (n_row, n_col, Row, Col, head,
+ min_score, n_col2-k, max_deg) ;
+#endif /* NDEBUG */
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ /* frontal matrix can have more pivot cols than pivot rows for */
+ /* singular matrices. */
+
+ /* number of candidate pivot columns */
+ Front_npivcol [nfr] = pivot_col_thickness ;
+
+ /* all rows (not just size of contrib. block) */
+ Front_nrows [nfr] = pivot_row_thickness ;
+
+ /* all cols */
+ Front_ncols [nfr] = pivot_col_thickness + pivot_row_degree ;
+
+ Front_parent [nfr] = EMPTY ;
+
+ pivot_row_thickness -= pivot_col_thickness ;
+ DEBUG1 (("Front "ID" Pivot_row_thickness after pivot cols elim: "ID"\n",
+ nfr, pivot_row_thickness)) ;
+ pivot_row_thickness = MAX (0, pivot_row_thickness) ;
+ /* ------------------ */
+
+ /* === Resurrect the new pivot row ================================== */
+
+ if (pivot_row_degree > 0
+ /* ------------------ */
+ /* added for UMFPACK: */
+ && pivot_row_thickness > 0
+ /* ------------------ */
+ )
+ {
+ /* update pivot row length to reflect any cols that were killed */
+ /* during super-col detection and mass elimination */
+ Row [pivot_row].start = pivot_row_start ;
+ Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
+ Row [pivot_row].shared1.degree = pivot_row_degree ;
+ Row [pivot_row].shared2.mark = 0 ;
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Row [pivot_row].thickness = pivot_row_thickness ;
+ Row [pivot_row].front = nfr ;
+ /* ------------------ */
+ /* pivot row is no longer dead */
+ }
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+
+#ifndef NDEBUG
+ DEBUG1 (("Front "ID" : "ID" "ID" "ID" ", nfr,
+ Front_npivcol [nfr], Front_nrows [nfr], Front_ncols [nfr])) ;
+ DEBUG1 ((" cols:[ ")) ;
+ debug_d = 0 ;
+ for (col = Front_cols [nfr] ; col != EMPTY ; col = Col [col].nextcol)
+ {
+ DEBUG1 ((" "ID, col)) ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (COL_IS_DEAD (col)) ;
+ debug_d++ ;
+ ASSERT (debug_d <= pivot_col_thickness) ;
+ }
+ ASSERT (debug_d == pivot_col_thickness) ;
+ DEBUG1 ((" ]\n ")) ;
+#endif
+ nfr++ ; /* one more front */
+ /* ------------------ */
+
+ }
+
+ /* === All principal columns have now been ordered ====================== */
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ *p_nfr = nfr ;
+ /* ------------------ */
+
+ return (ngarbage) ;
+}
+
+
+/* ========================================================================== */
+/* === order_children deleted for UMFPACK =================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === detect_super_cols ==================================================== */
+/* ========================================================================== */
+
+/*
+ Detects supercolumns by finding matches between columns in the hash buckets.
+ Check amongst columns in the set A [row_start ... row_start + row_length-1].
+ The columns under consideration are currently *not* in the degree lists,
+ and have already been placed in the hash buckets.
+
+ The hash bucket for columns whose hash function is equal to h is stored
+ as follows:
+
+ if head [h] is >= 0, then head [h] contains a degree list, so:
+
+ head [h] is the first column in degree bucket h.
+ Col [head [h]].headhash gives the first column in hash bucket h.
+
+ otherwise, the degree list is empty, and:
+
+ -(head [h] + 2) is the first column in hash bucket h.
+
+ For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
+ column" pointer. Col [c].shared3.hash is used instead as the hash number
+ for that column. The value of Col [c].shared4.hash_next is the next column
+ in the same hash bucket.
+
+ Assuming no, or "few" hash collisions, the time taken by this routine is
+ linear in the sum of the sizes (lengths) of each column whose score has
+ just been computed in the approximate degree computation.
+ Not user-callable.
+*/
+
+PRIVATE void detect_super_cols
+(
+ /* === Parameters ======================================================= */
+
+#ifndef NDEBUG
+ /* these two parameters are only needed when debugging is enabled: */
+ Int n_col, /* number of columns of A */
+ Colamd_Row Row [], /* of size n_row+1 */
+#endif /* NDEBUG */
+
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* row indices of A */
+ Int head [], /* head of degree lists and hash buckets */
+ Int row_start, /* pointer to set of columns to check */
+ Int row_length /* number of columns to check */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int hash ; /* hash value for a column */
+ Int *rp ; /* pointer to a row */
+ Int c ; /* a column index */
+ Int super_c ; /* column index of the column to absorb into */
+ Int *cp1 ; /* column pointer for column super_c */
+ Int *cp2 ; /* column pointer for column c */
+ Int length ; /* length of column super_c */
+ Int prev_c ; /* column preceding c in hash bucket */
+ Int i ; /* loop counter */
+ Int *rp_end ; /* pointer to the end of the row */
+ Int col ; /* a column index in the row to check */
+ Int head_column ; /* first column in hash bucket or degree list */
+ Int first_col ; /* first column in hash bucket */
+
+ /* === Consider each column in the row ================================== */
+
+ rp = &A [row_start] ;
+ rp_end = rp + row_length ;
+ while (rp < rp_end)
+ {
+ col = *rp++ ;
+ if (COL_IS_DEAD (col))
+ {
+ continue ;
+ }
+
+ /* get hash number for this column */
+ hash = Col [col].shared3.hash ;
+ ASSERT (hash <= n_col) ;
+
+ /* === Get the first column in this hash bucket ===================== */
+
+ head_column = head [hash] ;
+ if (head_column > EMPTY)
+ {
+ first_col = Col [head_column].shared3.headhash ;
+ }
+ else
+ {
+ first_col = - (head_column + 2) ;
+ }
+
+ /* === Consider each column in the hash bucket ====================== */
+
+ for (super_c = first_col ; super_c != EMPTY ;
+ super_c = Col [super_c].shared4.hash_next)
+ {
+ ASSERT (COL_IS_ALIVE (super_c)) ;
+ ASSERT (Col [super_c].shared3.hash == hash) ;
+ length = Col [super_c].length ;
+
+ /* prev_c is the column preceding column c in the hash bucket */
+ prev_c = super_c ;
+
+ /* === Compare super_c with all columns after it ================ */
+
+ for (c = Col [super_c].shared4.hash_next ;
+ c != EMPTY ; c = Col [c].shared4.hash_next)
+ {
+ ASSERT (c != super_c) ;
+ ASSERT (COL_IS_ALIVE (c)) ;
+ ASSERT (Col [c].shared3.hash == hash) ;
+
+ /* not identical if lengths or scores are different */
+ if (Col [c].length != length ||
+ Col [c].shared2.score != Col [super_c].shared2.score)
+ {
+ prev_c = c ;
+ continue ;
+ }
+
+ /* compare the two columns */
+ cp1 = &A [Col [super_c].start] ;
+ cp2 = &A [Col [c].start] ;
+
+ for (i = 0 ; i < length ; i++)
+ {
+ /* the columns are "clean" (no dead rows) */
+ ASSERT (ROW_IS_ALIVE (*cp1)) ;
+ ASSERT (ROW_IS_ALIVE (*cp2)) ;
+ /* row indices will same order for both supercols, */
+ /* no gather scatter nessasary */
+ if (*cp1++ != *cp2++)
+ {
+ break ;
+ }
+ }
+
+ /* the two columns are different if the for-loop "broke" */
+ if (i != length)
+ {
+ prev_c = c ;
+ continue ;
+ }
+
+ /* === Got it! two columns are identical =================== */
+
+ ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
+
+ Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
+ Col [c].shared1.parent = super_c ;
+ KILL_NON_PRINCIPAL_COL (c) ;
+
+ Col [c].shared2.order = EMPTY ;
+ /* remove c from hash bucket */
+ Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ /* add c to end of list of super_c */
+ ASSERT (Col [super_c].lastcol >= 0) ;
+ ASSERT (Col [super_c].lastcol < n_col) ;
+ Col [Col [super_c].lastcol].nextcol = c ;
+ Col [super_c].lastcol = Col [c].lastcol ;
+#ifndef NDEBUG
+ /* dump the supercolumn */
+ DEBUG1 (("Super")) ;
+ dump_super (super_c, Col, n_col) ;
+#endif
+ /* ------------------ */
+
+ }
+ }
+
+ /* === Empty this hash bucket ======================================= */
+
+ if (head_column > EMPTY)
+ {
+ /* corresponding degree list "hash" is not empty */
+ Col [head_column].shared3.headhash = EMPTY ;
+ }
+ else
+ {
+ /* corresponding degree list "hash" is empty */
+ head [hash] = EMPTY ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === garbage_collection =================================================== */
+/* ========================================================================== */
+
+/*
+ Defragments and compacts columns and rows in the workspace A. Used when
+ all avaliable memory has been used while performing row merging. Returns
+ the index of the first free position in A, after garbage collection. The
+ time taken by this routine is linear is the size of the array A, which is
+ itself linear in the number of nonzeros in the input matrix.
+ Not user-callable.
+*/
+
+PRIVATE Int garbage_collection /* returns the new value of pfree */
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows */
+ Int n_col, /* number of columns */
+ Colamd_Row Row [], /* row info */
+ Colamd_Col Col [], /* column info */
+ Int A [], /* A [0 ... Alen-1] holds the matrix */
+ Int *pfree /* &A [0] ... pfree is in use */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int *psrc ; /* source pointer */
+ Int *pdest ; /* destination pointer */
+ Int j ; /* counter */
+ Int r ; /* a row index */
+ Int c ; /* a column index */
+ Int length ; /* length of a row or column */
+
+#ifndef NDEBUG
+ Int debug_rows ;
+ DEBUG2 (("Defrag..\n")) ;
+ for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
+ debug_rows = 0 ;
+#endif /* NDEBUG */
+
+ /* === Defragment the columns =========================================== */
+
+ pdest = &A[0] ;
+ for (c = 0 ; c < n_col ; c++)
+ {
+ if (COL_IS_ALIVE (c))
+ {
+ psrc = &A [Col [c].start] ;
+
+ /* move and compact the column */
+ ASSERT (pdest <= psrc) ;
+ Col [c].start = (Int) (pdest - &A [0]) ;
+ length = Col [c].length ;
+ for (j = 0 ; j < length ; j++)
+ {
+ r = *psrc++ ;
+ if (ROW_IS_ALIVE (r))
+ {
+ *pdest++ = r ;
+ }
+ }
+ Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
+ }
+ }
+
+ /* === Prepare to defragment the rows =================================== */
+
+ for (r = 0 ; r < n_row ; r++)
+ {
+ if (ROW_IS_ALIVE (r))
+ {
+ if (Row [r].length == 0)
+ {
+ /* this row is of zero length. cannot compact it, so kill it */
+ DEBUG3 (("Defrag row kill\n")) ;
+ KILL_ROW (r) ;
+ }
+ else
+ {
+ /* save first column index in Row [r].shared2.first_column */
+ psrc = &A [Row [r].start] ;
+ Row [r].shared2.first_column = *psrc ;
+ ASSERT (ROW_IS_ALIVE (r)) ;
+ /* flag the start of the row with the one's complement of row */
+ *psrc = ONES_COMPLEMENT (r) ;
+
+#ifndef NDEBUG
+ debug_rows++ ;
+#endif /* NDEBUG */
+
+ }
+ }
+ }
+
+ /* === Defragment the rows ============================================== */
+
+ psrc = pdest ;
+ while (psrc < pfree)
+ {
+ /* find a negative number ... the start of a row */
+ if (*psrc++ < 0)
+ {
+ psrc-- ;
+ /* get the row index */
+ r = ONES_COMPLEMENT (*psrc) ;
+ ASSERT (r >= 0 && r < n_row) ;
+ /* restore first column index */
+ *psrc = Row [r].shared2.first_column ;
+ ASSERT (ROW_IS_ALIVE (r)) ;
+
+ /* move and compact the row */
+ ASSERT (pdest <= psrc) ;
+ Row [r].start = (Int) (pdest - &A [0]) ;
+ length = Row [r].length ;
+ for (j = 0 ; j < length ; j++)
+ {
+ c = *psrc++ ;
+ if (COL_IS_ALIVE (c))
+ {
+ *pdest++ = c ;
+ }
+ }
+ Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
+
+#ifndef NDEBUG
+ debug_rows-- ;
+#endif /* NDEBUG */
+
+ }
+ }
+ /* ensure we found all the rows */
+ ASSERT (debug_rows == 0) ;
+
+ /* === Return the new value of pfree ==================================== */
+
+ return ((Int) (pdest - &A [0])) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+ Clears the Row [].shared2.mark array, and returns the new tag_mark.
+ Return value is the new tag_mark. Not user-callable.
+*/
+
+PRIVATE Int clear_mark /* return the new value for tag_mark */
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows in A */
+ Colamd_Row Row [] /* Row [0 ... n-1].shared2.mark is set to zero */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int r ;
+
+ for (r = 0 ; r < n_row ; r++)
+ {
+ if (ROW_IS_ALIVE (r))
+ {
+ Row [r].shared2.mark = 0 ;
+ }
+ }
+
+ /* ------------------ */
+ return (1) ;
+ /* ------------------ */
+
+}
+
+
+/* ========================================================================== */
+/* === print_report removed for UMFPACK ===================================== */
+/* ========================================================================== */
+
+
+
+/* ========================================================================== */
+/* === colamd debugging routines ============================================ */
+/* ========================================================================== */
+
+/* When debugging is disabled, the remainder of this file is ignored. */
+
+#ifndef NDEBUG
+
+
+/* ========================================================================== */
+/* === debug_structures ===================================================== */
+/* ========================================================================== */
+
+/*
+ At this point, all empty rows and columns are dead. All live columns
+ are "clean" (containing no dead rows) and simplicial (no supercolumns
+ yet). Rows may contain dead columns, but all live rows contain at
+ least one live column.
+*/
+
+PRIVATE void debug_structures
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int n_col2
+)
+{
+ /* === Local variables ================================================== */
+
+ Int i ;
+ Int c ;
+ Int *cp ;
+ Int *cp_end ;
+ Int len ;
+ Int score ;
+ Int r ;
+ Int *rp ;
+ Int *rp_end ;
+ Int deg ;
+
+ /* === Check A, Row, and Col ============================================ */
+
+ for (c = 0 ; c < n_col ; c++)
+ {
+ if (COL_IS_ALIVE (c))
+ {
+ len = Col [c].length ;
+ score = Col [c].shared2.score ;
+ DEBUG4 (("initial live col "ID" "ID" "ID"\n", c, len, score)) ;
+ ASSERT (len > 0) ;
+ ASSERT (score >= 0) ;
+ ASSERT (Col [c].shared1.thickness == 1) ;
+ cp = &A [Col [c].start] ;
+ cp_end = cp + len ;
+ while (cp < cp_end)
+ {
+ r = *cp++ ;
+ ASSERT (ROW_IS_ALIVE (r)) ;
+ }
+ }
+ else
+ {
+ i = Col [c].shared2.order ;
+ ASSERT (i >= n_col2 && i < n_col) ;
+ }
+ }
+
+ for (r = 0 ; r < n_row ; r++)
+ {
+ if (ROW_IS_ALIVE (r))
+ {
+ i = 0 ;
+ len = Row [r].length ;
+ deg = Row [r].shared1.degree ;
+ ASSERT (len > 0) ;
+ ASSERT (deg > 0) ;
+ rp = &A [Row [r].start] ;
+ rp_end = rp + len ;
+ while (rp < rp_end)
+ {
+ c = *rp++ ;
+ if (COL_IS_ALIVE (c))
+ {
+ i++ ;
+ }
+ }
+ ASSERT (i > 0) ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === debug_deg_lists ====================================================== */
+/* ========================================================================== */
+
+/*
+ Prints the contents of the degree lists. Counts the number of columns
+ in the degree list and compares it to the total it should have. Also
+ checks the row degrees.
+*/
+
+PRIVATE void debug_deg_lists
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int head [],
+ Int min_score,
+ Int should,
+ Int max_deg
+)
+{
+ /* === Local variables ================================================== */
+
+ Int deg ;
+ Int col ;
+ Int have ;
+ Int row ;
+
+ /* === Check the degree lists =========================================== */
+
+ if (n_col > 10000 && UMF_debug <= 0)
+ {
+ return ;
+ }
+ have = 0 ;
+ DEBUG4 (("Degree lists: "ID"\n", min_score)) ;
+ for (deg = 0 ; deg <= n_col ; deg++)
+ {
+ col = head [deg] ;
+ if (col == EMPTY)
+ {
+ continue ;
+ }
+ DEBUG4 ((ID":", deg)) ;
+ while (col != EMPTY)
+ {
+ DEBUG4 ((" "ID, col)) ;
+ have += Col [col].shared1.thickness ;
+ ASSERT (COL_IS_ALIVE (col)) ;
+ col = Col [col].shared4.degree_next ;
+ }
+ DEBUG4 (("\n")) ;
+ }
+ DEBUG4 (("should "ID" have "ID"\n", should, have)) ;
+ ASSERT (should == have) ;
+
+ /* === Check the row degrees ============================================ */
+
+ if (n_row > 10000 && UMF_debug <= 0)
+ {
+ return ;
+ }
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (ROW_IS_ALIVE (row))
+ {
+ ASSERT (Row [row].shared1.degree <= max_deg) ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === debug_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+ Ensures that the tag_mark is less that the maximum and also ensures that
+ each entry in the mark array is less than the tag mark.
+*/
+
+PRIVATE void debug_mark
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Colamd_Row Row [],
+ Int tag_mark,
+ Int max_mark
+)
+{
+ /* === Local variables ================================================== */
+
+ Int r ;
+
+ /* === Check the Row marks ============================================== */
+
+ ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
+ if (n_row > 10000 && UMF_debug <= 0)
+ {
+ return ;
+ }
+ for (r = 0 ; r < n_row ; r++)
+ {
+ ASSERT (Row [r].shared2.mark < tag_mark) ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === debug_matrix ========================================================= */
+/* ========================================================================== */
+
+/*
+ Prints out the contents of the columns and the rows.
+*/
+
+PRIVATE void debug_matrix
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A []
+)
+{
+ /* === Local variables ================================================== */
+
+ Int r ;
+ Int c ;
+ Int *rp ;
+ Int *rp_end ;
+ Int *cp ;
+ Int *cp_end ;
+
+ /* === Dump the rows and columns of the matrix ========================== */
+
+ if (UMF_debug < 3)
+ {
+ return ;
+ }
+ DEBUG3 (("DUMP MATRIX:\n")) ;
+ for (r = 0 ; r < n_row ; r++)
+ {
+ DEBUG3 (("Row "ID" alive? "ID"\n", r, ROW_IS_ALIVE (r))) ;
+ if (ROW_IS_DEAD (r))
+ {
+ continue ;
+ }
+
+ /* ------------------ */
+ /* changed for UMFPACK: */
+ DEBUG3 (("start "ID" length "ID" degree "ID" thickness "ID"\n",
+ Row [r].start, Row [r].length, Row [r].shared1.degree,
+ Row [r].thickness)) ;
+ /* ------------------ */
+
+ rp = &A [Row [r].start] ;
+ rp_end = rp + Row [r].length ;
+ while (rp < rp_end)
+ {
+ c = *rp++ ;
+ DEBUG4 ((" "ID" col "ID"\n", COL_IS_ALIVE (c), c)) ;
+ }
+ }
+
+ for (c = 0 ; c < n_col ; c++)
+ {
+ DEBUG3 (("Col "ID" alive? "ID"\n", c, COL_IS_ALIVE (c))) ;
+ if (COL_IS_DEAD (c))
+ {
+ continue ;
+ }
+ /* ------------------ */
+ /* changed for UMFPACK: */
+ DEBUG3 (("start "ID" length "ID" shared1[thickness,parent] "ID
+ " shared2 [order,score] "ID"\n", Col [c].start, Col [c].length,
+ Col [c].shared1.thickness, Col [c].shared2.score));
+ /* ------------------ */
+ cp = &A [Col [c].start] ;
+ cp_end = cp + Col [c].length ;
+ while (cp < cp_end)
+ {
+ r = *cp++ ;
+ DEBUG4 ((" "ID" row "ID"\n", ROW_IS_ALIVE (r), r)) ;
+ }
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ DEBUG1 (("Col")) ;
+ dump_super (c, Col, n_col) ;
+ /* ------------------ */
+
+ }
+}
+
+/* ------------------ */
+/* dump_super added for UMFPACK: */
+PRIVATE void dump_super
+(
+ Int super_c,
+ Colamd_Col Col [],
+ Int n_col
+)
+{
+ Int col, ncols ;
+
+ DEBUG1 ((" =[ ")) ;
+ ncols = 0 ;
+ for (col = super_c ; col != EMPTY ; col = Col [col].nextcol)
+ {
+ DEBUG1 ((" "ID, col)) ;
+ ASSERT (col >= 0 && col < n_col) ;
+ if (col != super_c)
+ {
+ ASSERT (COL_IS_DEAD (col)) ;
+ }
+ if (Col [col].nextcol == EMPTY)
+ {
+ ASSERT (col == Col [super_c].lastcol) ;
+ }
+ ncols++ ;
+ ASSERT (ncols <= Col [super_c].shared1.thickness) ;
+ }
+ ASSERT (ncols == Col [super_c].shared1.thickness) ;
+ DEBUG1 (("]\n")) ;
+}
+/* ------------------ */
+
+
+#endif /* NDEBUG */
+
diff --git a/src/sparse-matrix/umfpack/umf_create_element.c b/src/sparse-matrix/umfpack/umf_create_element.c
new file mode 100644
index 0000000..623693b
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_create_element.c
@@ -0,0 +1,534 @@
+/* ========================================================================== */
+/* === UMF_create_element =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* 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"
+#include "umf_blas3_update.h"
+
+GLOBAL Int UMF_create_element
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int j, col, row, *Fcols, *Frows, fnrows, fncols, *Cols, len, needunits, t1,
+ t2, size, e, i, *E, *Fcpos, *Frpos, *Rows, eloc, fnrows_max, f,
+ got_memory, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, max_mark,
+ *Col_degree, *Col_tlen, nn, n_row, n_col ;
+ Entry *C, *Fcol ;
+ Element *ep ;
+ Unit *p, *Memory ;
+ Tuple *tp, *tp1, *tp2, tuple, *tpend ;
+#ifndef NDEBUG
+ double gprob_save ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* apply pending updates, if any */
+ /* ---------------------------------------------------------------------- */
+
+ if (Work->fnpiv > 0)
+ {
+ UMF_blas3_update (Work) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG2 (("FRONTAL WRAPUP\n")) ;
+ Col_degree = Numeric->Cperm ;
+ Row_degree = Numeric->Rperm ;
+ Row_tuples = Numeric->Uip ;
+ Row_tlen = Numeric->Uilen ;
+ 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 ;
+ fnrows_max = Work->fnrows_max ;
+
+ tp = (Tuple *) NULL ;
+ tp1 = (Tuple *) NULL ;
+ tp2 = (Tuple *) NULL ;
+
+ /* ---------------------------------------------------------------------- */
+ /* add the current frontal matrix to the degrees of each column, */
+ /* and place the modified columns back in the degree lists */
+ /* ---------------------------------------------------------------------- */
+
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ 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 */
+ Work->cdeg0 = 1 ;
+ for (e = 0 ; 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 */
+ Work->rdeg0 = 1 ;
+ for (e = 0 ; e <= Work->nel ; e++)
+ {
+ if (E [e])
+ {
+ ep = (Element *) (Memory + E [e]) ;
+ ep->rdeg = 0 ;
+ }
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* clear row/col offsets */
+ /* ---------------------------------------------------------------------- */
+
+ if (!Work->pivrow_in_front)
+ {
+ for (j = 0 ; j < fncols ; j++)
+ {
+ Fcpos [Fcols [j]] = EMPTY ;
+ }
+ }
+
+ if (!Work->pivcol_in_front)
+ {
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ needunits = 0 ;
+ got_memory = FALSE ;
+ eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+ &needunits, &ep) ;
+
+ if (!eloc)
+ {
+ /* do garbage collection, realloc, and try again */
+ if (!UMF_get_memory (Numeric, Work, needunits))
+ {
+ return (FALSE) ; /* out of memory */
+ }
+ got_memory = TRUE ;
+ Memory = Numeric->Memory ;
+#ifndef NDEBUG
+ gprob_save = UMF_gprob ;
+ UMF_gprob = 0 ;
+#endif
+ eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+ &needunits, &ep) ;
+ ASSERT (eloc >= 0) ;
+ if (!eloc)
+ {
+ return (FALSE) ; /* out of memory */
+ }
+#ifndef NDEBUG
+ UMF_gprob = gprob_save ;
+#endif
+ }
+
+ 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 <= n_col + MIN (n_row,n_col)) ;
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Rows [i] = Frows [i] ;
+ }
+ for (i = 0 ; i < fncols ; i++)
+ {
+ Cols [i] = Fcols [i] ;
+ }
+ Fcol = Work->Fx ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ C [i] = Fcol [i] ;
+ }
+ Fcol += fnrows_max ;
+ C += fnrows ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* 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
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* might not have enough space for each 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)) ;
+ 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) DEBUG1 (("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, reconstruct all tuple lists, and return */
+ return (UMF_get_memory (Numeric, Work, 0)) ;
+ }
+ 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) DEBUG1 (("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, reconstruct all tuple lists, and return */
+ return (UMF_get_memory (Numeric, Work, 0)) ;
+ }
+ 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, TRUE) ;
+ }
+ 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) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_dump.c b/src/sparse-matrix/umfpack/umf_dump.c
new file mode 100644
index 0000000..6428239
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_dump.c
@@ -0,0 +1,1163 @@
+/* ========================================================================== */
+/* === UMF_dump ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* These routines, and external variables, are used only when debugging. */
+/* If debugging is disabled (for normal operation) then this entire file */
+/* becomes empty */
+
+#include "umf_internal.h"
+
+#ifndef NDEBUG
+
+/* These global debugging variables and arrays do not exist if debugging */
+/* is disabled at compile time (which is the default). */
+GLOBAL Int UMF_debug = -1 ;
+GLOBAL Int UMF_nbug = -999 ;
+GLOBAL Int UMF_fbug = -999 ;
+GLOBAL Int UMF_allocfail = FALSE ;
+GLOBAL double UMF_gprob = -1.0 ;
+
+/* static debugging arrays used only in UMF_dump_rowcol */
+PRIVATE Int UMF_DBflag = 0 ;
+PRIVATE Int UMF_DBpacked [UMF_DBMAX+1] ;
+PRIVATE Int UMF_DBscatter [UMF_DBMAX+1] ;
+
+/* ========================================================================== */
+/* === UMF_DBinit =========================================================== */
+/* ========================================================================== */
+
+/* clear the debugging arrays */
+
+PRIVATE void UMF_DBinit
+(
+ void
+)
+{
+ Int i ;
+
+ /* Int_MAX is defined in umfpack.h */
+ if (UMF_DBflag < 1 || UMF_DBflag == Int_MAX)
+ {
+ /* clear the debugging arrays */
+ UMF_DBflag = 0 ;
+ for (i = 0 ; i <= UMF_DBMAX ; i++)
+ {
+ UMF_DBscatter [i] = 0 ;
+ UMF_DBpacked [i] = 0 ;
+ }
+ }
+
+ UMF_DBflag++ ;
+
+ /* UMF_DBflag > UMF_DBscatter [0...UMF_DBmax] is now true */
+}
+
+/* ========================================================================== */
+/* === UMF_dump_dense ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_dense
+(
+ Entry *Fx,
+ Int dim,
+ Int m,
+ Int n
+)
+{
+
+ /* dump Fx [1..m,1..n], with column dimenstion dim */
+ Int i, j;
+
+ if (UMF_debug < 7) return ;
+ if (!Fx)
+ {
+ DEBUG7 (("No dense matrix allocated\n")) ;
+ return ;
+ }
+ DEBUG8 ((" dimension= "ID" rows= "ID" cols= "ID"\n", dim, m, n)) ;
+
+ for (i = 0 ; i < m ; i++)
+ {
+ DEBUG9 ((ID": ", i)) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ EDEBUG9 (Fx [i+j*dim]) ;
+ if (j % 6 == 5) DEBUG9 (("\n ")) ;
+ }
+ DEBUG9 (("\n")) ;
+ }
+
+ for (i = 0 ; i < m ; i++)
+ {
+ for (j = 0 ; j < n ; j++)
+ {
+ if (IS_ZERO (Fx [i+j*dim]))
+ {
+ DEBUG8 ((".")) ;
+ }
+ else
+ {
+ DEBUG8 (("X")) ;
+ }
+ }
+ DEBUG8 (("\n")) ;
+ }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_element ===================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_element
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int e,
+ Int clean
+)
+{
+
+ Int i, j, k, *Rows, *Cols, nrows, ncols, *E, row, col,
+ *Row_degree, *Col_degree ;
+ Entry *C ;
+ Element *ep ;
+ Unit *p ;
+
+ if (UMF_debug < 7) return ;
+ DEBUG7 (("\n====================ELEMENT: "ID" ", e)) ;
+ if (!Numeric || !Work || !Numeric->Memory)
+ {
+ DEBUG7 ((" No Numeric, Work\n")) ;
+ return ;
+ }
+ DEBUG7 ((" nel: "ID" of "ID, e, Work->nel)) ;
+ if (e <= Work->nelorig) DEBUG7 ((" Original ")) ;
+ E = Work->E ;
+ if (!E)
+ {
+ DEBUG7 ((" No elements\n")) ;
+ return ;
+ }
+ if (e < 0 || e > Work->nel)
+ {
+ DEBUG7 (("e out of range!\n")) ;
+ return ;
+ }
+ if (!E [e])
+ {
+ DEBUG7 ((" deallocated\n")) ;
+ return ;
+ }
+ DEBUG7 (("\n")) ;
+ Col_degree = Numeric->Cperm ;
+ Row_degree = Numeric->Rperm ;
+
+ p = Numeric->Memory + E [e] ;
+ DEBUG7 (("ep "ID"\n", p-Numeric->Memory)) ;
+ GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ;
+ DEBUG7 (("nrows "ID" nrowsleft "ID"\n", nrows, ep->nrowsleft)) ;
+ DEBUG7 (("ncols "ID" ncolsleft "ID"\n", ncols, ep->ncolsleft)) ;
+ DEBUG7 (("cdeg-cdeg0 "ID" rdeg-rdeg0 "ID" next "ID"\n",
+ ep->cdeg - Work->cdeg0, ep->rdeg - Work->rdeg0, ep->next)) ;
+
+ DEBUG8 (("rows: ")) ;
+ k = 0 ;
+ for (i = 0 ; i < ep->nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0)
+ {
+ DEBUG8 ((" "ID, row)) ;
+ ASSERT (row < Work->n_row) ;
+ if ((k++ % 10) == 9) DEBUG8 (("\n")) ;
+ ASSERT (IMPLIES (clean, NON_PIVOTAL_ROW (row))) ;
+ }
+ }
+
+ DEBUG8 (("\ncols: ")) ;
+ k = 0 ;
+ for (j = 0 ; j < ep->ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+ DEBUG8 ((" "ID, col)) ;
+ ASSERT (col < Work->n_col) ;
+ if ((k++ % 10) == 9) DEBUG8 (("\n")) ;
+ ASSERT (IMPLIES (clean, NON_PIVOTAL_COL (col))) ;
+ }
+ }
+
+ DEBUG8 (("\nvalues:\n")) ;
+ if (UMF_debug >= 9)
+ {
+ for (i = 0 ; i < ep->nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0)
+ {
+ DEBUG9 ((ID": ", row)) ;
+ k = 0 ;
+ for (j = 0 ; j < ep->ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+ EDEBUG9 (C [i+j*ep->nrows]) ;
+ if (k++ % 6 == 5) DEBUG9 (("\n ")) ;
+ }
+ }
+ DEBUG9 (("\n")) ;
+ }
+ }
+ }
+
+ DEBUG7 (("====================\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_rowcol ====================================================== */
+/* ========================================================================== */
+
+/* dump a row or a column, from one or more memory spaces */
+/* return exact degree */
+
+GLOBAL void UMF_dump_rowcol
+(
+ Int dumpwhich, /* 0 for row, 1 for column */
+ NumericType *Numeric,
+ WorkType *Work,
+ Int dumpindex, /* row or column index to dump */
+ Int check_degree /* true if degree is to be checked */
+)
+{
+ Int f, nrows, j, jj, len, e, deg, index, n_row, n_col, *Cols, *Rows, nn,
+ dumpdeg, ncols, preve, *E, tpi, *Pattern, approx_deg, not_in_use ;
+ Tuple *tp, *tend ;
+ Element *ep ;
+ Int *Row_tuples, *Row_degree, *Row_tlen ;
+ Int *Col_tuples, *Col_degree, *Col_tlen ;
+ Entry value, *C ;
+ Unit *p ;
+ Int is_there ;
+
+ /* clear the debugging arrays */
+ UMF_DBinit () ;
+
+ if (dumpwhich == 0)
+ {
+ DEBUG7 (("\n====================ROW: "ID, dumpindex)) ;
+ }
+ else
+ {
+ DEBUG7 (("\n====================COL: "ID, dumpindex)) ;
+ }
+
+ if (dumpindex == EMPTY)
+ {
+ DEBUG7 ((" (EMPTY)\n")) ;
+ return ;
+ }
+
+ deg = 0 ;
+ approx_deg = 0 ;
+
+ if (!Numeric || !Work)
+ {
+ DEBUG7 ((" No Numeric, Work\n")) ;
+ return ;
+ }
+
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ nn = MAX (n_row, n_col) ;
+ E = Work->E ;
+
+ Col_degree = Numeric->Cperm ;
+ Row_degree = Numeric->Rperm ;
+
+ Row_tuples = Numeric->Uip ;
+ Row_tlen = Numeric->Uilen ;
+ Col_tuples = Numeric->Lip ;
+ Col_tlen = Numeric->Lilen ;
+
+ if (!E
+ || !Row_tuples || !Row_degree || !Row_tlen
+ || !Col_tuples || !Col_degree || !Col_tlen)
+ {
+ DEBUG7 ((" No E, Rows, Cols\n")) ;
+ return ;
+ }
+
+ if (dumpwhich == 0)
+ {
+ /* dump a row */
+ ASSERT (dumpindex >= 0 && dumpindex < n_row) ;
+ if (!NON_PIVOTAL_ROW (dumpindex))
+ {
+ DEBUG7 ((" Pivotal\n")) ;
+ return ;
+ }
+ len = Row_tlen [dumpindex] ;
+ dumpdeg = Row_degree [dumpindex] ;
+ tpi = Row_tuples [dumpindex] ;
+ }
+ else
+ {
+ /* dump a column */
+ ASSERT (dumpindex >= 0 && dumpindex < n_col) ;
+ if (!NON_PIVOTAL_COL (dumpindex))
+ {
+ DEBUG7 ((" Pivotal\n")) ;
+ return ;
+ }
+ len = Col_tlen [dumpindex] ;
+ dumpdeg = Col_degree [dumpindex] ;
+ tpi = Col_tuples [dumpindex] ;
+ }
+
+ p = Numeric->Memory + tpi ;
+ tp = (Tuple *) p ;
+ if (!tpi)
+ {
+ DEBUG7 ((" Nonpivotal, No tuple list tuples "ID" tlen "ID"\n",
+ tpi, len)) ;
+ return ;
+ }
+ ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+ ASSERT (p < Numeric->Memory + Numeric->size) ;
+
+ DEBUG7 ((" degree: "ID" len: "ID"\n", dumpdeg, len)) ;
+ not_in_use = (p-1)->header.size - UNITS (Tuple, len) ;
+ DEBUG7 ((" Tuple list: p+1: "ID" size: "ID" units, "ID" not in use\n",
+ p-Numeric->Memory, (p-1)->header.size, not_in_use)) ;
+ ASSERT (not_in_use >= 0) ;
+ tend = tp + len ;
+ preve = 0 ;
+ for ( ; tp < tend ; tp++)
+ {
+ /* row/col of element e, offset is f: */
+ /* DEBUG8 ((" (tp="ID")\n", tp)) ; */
+ e = tp->e ;
+ f = tp->f ;
+ DEBUG8 ((" (e="ID", f="ID")\n", e, f)) ;
+ ASSERT (e > 0 && e <= Work->nel) ;
+ /* dump the pattern and values */
+ if (E [e])
+ {
+ p = Numeric->Memory + E [e] ;
+ GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ;
+ if (dumpwhich == 0)
+ {
+ Pattern = Cols ;
+ jj = ep->ncols ;
+ is_there = Rows [f] >= 0 ;
+ if (is_there) approx_deg += ep->ncolsleft ;
+ }
+ else
+ {
+ Pattern = Rows ;
+ jj = ep->nrows ;
+ is_there = Cols [f] >= 0 ;
+ if (is_there) approx_deg += ep->nrowsleft ;
+ }
+ if (!is_there)
+ {
+ DEBUG8 (("\t\tnot present\n")) ;
+ }
+ else
+ {
+ for (j = 0 ; j < jj ; j++)
+ {
+ index = Pattern [j] ;
+ value =
+ C [ (dumpwhich == 0) ? (f+nrows*j) : (j+nrows*f) ] ;
+ if (index >= 0)
+ {
+ DEBUG8 (("\t\t"ID":", index)) ;
+ EDEBUG8 (value) ;
+ DEBUG8 (("\n")) ;
+ if (dumpwhich == 0)
+ {
+ /* col must be in the range 0..n_col-1 */
+ ASSERT (index < n_col) ;
+ }
+ else
+ {
+ /* row must be in the range 0..n_row-1 */
+ ASSERT (index < n_row) ;
+ }
+
+ if (nn <= UMF_DBMAX)
+ {
+ if (UMF_DBscatter [index] != UMF_DBflag)
+ {
+ UMF_DBpacked [deg++] = index ;
+ UMF_DBscatter [index] = UMF_DBflag ;
+ }
+ }
+ }
+ }
+ }
+ /* the (e,f) tuples should be in order of their creation */
+ /* this means that garbage collection will not jumble them */
+ ASSERT (preve < e) ;
+ preve = e ;
+ }
+ else
+ {
+ DEBUG8 (("\t\tdeallocated\n")) ;
+ }
+ }
+
+ if (nn <= UMF_DBMAX)
+ {
+ if (deg > 0)
+ {
+ DEBUG7 ((" Assembled, actual deg: "ID" : ", deg)) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ index = UMF_DBpacked [j] ;
+ DEBUG8 ((ID" ", index)) ;
+ if (j % 20 == 19) DEBUG8 (("\n ")) ;
+ ASSERT (UMF_DBscatter [index] == UMF_DBflag) ;
+ }
+ DEBUG7 (("\n")) ;
+ }
+ }
+
+ if (check_degree)
+ {
+ DEBUG8 ((" approx_deg "ID" dumpdeg "ID"\n", approx_deg, dumpdeg)) ;
+ ASSERT (approx_deg == dumpdeg) ;
+ }
+
+ DEBUG7 (("====================\n")) ;
+
+ /* deg is now the exact degree */
+ /* if nn <= UMF_DBMAX, then UMF_DBscatter [i] == UMF_DBflag for every i */
+ /* in the row or col, and != UMF_DBflag if not */
+
+ return ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_matrix ====================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_matrix
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int check_degree
+)
+{
+
+ Int e, row, col, intfrag, frag, n_row, n_col, *E, fullsize, actualsize ;
+ Element *ep ;
+ Unit *p ;
+
+ DEBUG6 (("=================================================== MATRIX:\n")) ;
+ if (!Numeric || !Work)
+ {
+ DEBUG6 (("No Numeric or Work allocated\n")) ;
+ return ;
+ }
+ if (!Numeric->Memory)
+ {
+ DEBUG6 (("No Numeric->Memory\n")) ;
+ return ;
+ }
+
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ DEBUG6 (("n_row "ID" n_col "ID" nz "ID"\n", n_row, n_col, Work->nz)) ;
+ DEBUG6 (("============================ ELEMENTS: "ID" \n", Work->nel)) ;
+ intfrag = 0 ;
+ E = Work->E ;
+ if (!E)
+ {
+ DEBUG6 (("No elements allocated\n")) ;
+ }
+ else
+ {
+ for (e = 0 ; e <= Work->nel ; e++)
+ {
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+ if (e > 0 && E [e])
+ {
+ p = Numeric->Memory + E [e] ;
+ ep = (Element *) p ;
+ ASSERT (ep->nrowsleft > 0 || ep->ncolsleft > 0) ;
+ fullsize = GET_BLOCK_SIZE (p) ;
+ actualsize = GET_ELEMENT_SIZE (ep->nrowsleft,ep->ncolsleft);
+ frag = fullsize - actualsize ;
+ intfrag += frag ;
+ DEBUG7 (("dump el: "ID", full "ID" actual "ID" frag: "ID
+ " intfrag: "ID"\n", e, fullsize, actualsize, frag,
+ intfrag)) ;
+ }
+ }
+ }
+
+ DEBUG6 (("CURRENT INTERNAL FRAG in elements: "ID" \n", intfrag)) ;
+
+
+
+ DEBUG6 (("======================================== ROWS: "ID"\n", n_row)) ;
+ UMF_debug -= 2 ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ UMF_dump_rowcol (0, Numeric, Work, row, check_degree) ;
+ }
+ UMF_debug += 2 ;
+ DEBUG6 (("======================================== COLS: "ID"\n", n_col)) ;
+ UMF_debug -= 2 ;
+ for (col = 0 ; col < n_col ; col++)
+ {
+ UMF_dump_rowcol (1, Numeric, Work, col, check_degree) ;
+ }
+ UMF_debug += 2 ;
+ DEBUG6 (("============================================= END OF MATRIX:\n"));
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_current_front =============================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_current_front
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int check
+)
+{
+ Entry *Fx ;
+ Int fnrows_max, fncols_max, fnrows, fncols, fnpiv, *Frows, *Fcols,
+ i, j, *Fcpos, *Frpos ;
+ if (!Work) return ;
+ DEBUG7 (("\n\n========CURRENT FRONTAL MATRIX:\n")) ;
+
+ Fx = Work->Fx ;
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+ Frpos = Work->Frpos ;
+ Fcpos = Work->Fcpos ;
+ fnrows_max = Work->fnrows_max ;
+ fncols_max = Work->fncols_max ;
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ fnpiv = Work->fnpiv ;
+
+ DEBUG6 (("=== fnpiv= "ID"\n", fnpiv)) ;
+ DEBUG6 (("fncols_max fnrows_max "ID" "ID"\n", fncols_max,fnrows_max)) ;
+ DEBUG6 (("fncols fnrows "ID" "ID"\n", fncols, fnrows)) ;
+ DEBUG6 (("Pivot row pattern:\n")) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ DEBUG7 ((ID" "ID" "ID" "ID"\n", j, Fcols [j], Fcpos [Fcols [j]],
+ j < fncols)) ;
+ if (check)
+ {
+ ASSERT (Fcols [j] >= 0 && Fcols [j] < Work->n_col) ;
+ }
+ ASSERT (Fcpos [Fcols [j]] == j * fnrows_max) ;
+ }
+ DEBUG6 (("Pivot col pattern:\n")) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG7 ((ID" "ID" "ID" "ID"\n", i, Frows [i], Frpos [Frows [i]],
+ i < fnrows)) ;
+ if (check)
+ {
+ ASSERT (Frows [i] >= 0 && Frows [i] < Work->n_row) ;
+ }
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+ if (UMF_debug < 7) return ;
+
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Fx, fnrows_max, fnrows, fncols) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Fx+(fncols_max-fnpiv)*fnrows_max, fnrows_max, fnrows,fnpiv);
+ DEBUG7 (("U block: ")) ;
+ UMF_dump_dense (Fx+(fnrows_max-fnpiv), fnrows_max, fnpiv, fncols) ;
+ if (fnpiv > 0)
+ {
+ DEBUG7 (("Pivot entry: ")) ;
+ EDEBUG7 (Fx [(fnrows_max-fnpiv)+(fncols_max-fnpiv)*fnrows_max]) ;
+ DEBUG7 (("\n")) ;
+ }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_lu ========================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_lu
+(
+ NumericType *Numeric
+)
+{
+ Int i, n_row, n_col, *Cperm, *Rperm ;
+
+ DEBUG6 (("=============================================== LU factors:\n")) ;
+ if (!Numeric)
+ {
+ DEBUG6 (("No LU factors allocated\n")) ;
+ return ;
+ }
+ n_row = Numeric->n_row ;
+ n_col = Numeric->n_col ;
+ DEBUG6 (("n_row: "ID" n_col: "ID"\n", n_row, n_col)) ;
+ DEBUG6 (("nLentries: "ID" nUentries: "ID"\n",
+ Numeric->nLentries, Numeric->nUentries)) ;
+
+ if (Numeric->Cperm)
+ {
+ Cperm = Numeric->Cperm ;
+ DEBUG7 (("Column permutations: (new: old)\n")) ;
+ for (i = 0 ; i < n_col ; i++)
+ {
+ if (Cperm [i] != EMPTY)
+ {
+ DEBUG7 ((ID": "ID"\n", i, Cperm [i])) ;
+ }
+ }
+ }
+ else
+ {
+ DEBUG7 (("No Numeric->Cperm allocatated\n")) ;
+ }
+
+ if (Numeric->Rperm)
+ {
+ Rperm = Numeric->Rperm ;
+ DEBUG7 (("row permutations: (new: old)\n")) ;
+ for (i = 0 ; i < n_row ; i++)
+ {
+ if (Rperm [i] != EMPTY)
+ {
+ DEBUG7 ((ID": "ID"\n", i, Rperm [i])) ;
+ }
+ }
+ }
+ else
+ {
+ DEBUG7 (("No Numeric->Rperm allocatated\n")) ;
+ }
+
+ DEBUG6 (("========================================= END OF LU factors:\n"));
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_memory ====================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_memory
+(
+ NumericType *Numeric
+)
+{
+
+ Unit *p ;
+ Int prevsize, s ;
+ Int found ;
+
+ if (!Numeric)
+ {
+ DEBUG6 (("No memory space S allocated\n")) ;
+ return ;
+ }
+
+ DEBUG6 (("\n ============================================== MEMORY:\n")) ;
+ if (!Numeric || !Numeric->Memory)
+ {
+ DEBUG6 (("No memory space Numeric allocated\n")) ;
+ return ;
+ }
+
+ DEBUG6 (("S: "ID"\n", (Int) Numeric)) ;
+ DEBUG6 (("S->ihead : "ID"\n", Numeric->ihead)) ;
+ DEBUG6 (("S->itail : "ID"\n", Numeric->itail)) ;
+ DEBUG6 (("S->size : "ID"\n", Numeric->size)) ;
+ DEBUG6 (("S->ngarbage : "ID"\n", Numeric->ngarbage)) ;
+ DEBUG6 (("S->nrealloc : "ID"\n", Numeric->nrealloc)) ;
+ DEBUG6 ((" in use at head : "ID"\n", Numeric->ihead)) ;
+ DEBUG6 ((" free space : "ID"\n",
+ Numeric->itail - Numeric->ihead)) ;
+ DEBUG6 ((" blocks in use at tail : "ID"\n",
+ Numeric->size - Numeric->itail)) ;
+ DEBUG6 ((" total in use : "ID"\n",
+ Numeric->size - (Numeric->itail - Numeric->ihead))) ;
+
+ prevsize = 0 ;
+ found = FALSE ;
+
+ ASSERT (0 <= Numeric->ihead) ;
+ ASSERT (Numeric->ihead <= Numeric->itail) ;
+ ASSERT (Numeric->itail <= Numeric->size) ;
+
+ p = Numeric->Memory + Numeric->itail ;
+
+ while (p < Numeric->Memory + Numeric->size)
+ {
+ DEBUG8 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID,
+ p-Numeric->Memory, p+1-Numeric->Memory,
+ p->header.prevsize, p->header.size)) ;
+ if (p->header.size < 0)
+ {
+ DEBUG8 ((" free")) ;
+ }
+
+ if (p == Numeric->Memory + Numeric->itail)
+ {
+ ASSERT (p->header.prevsize == 0) ;
+ }
+ else
+ {
+ ASSERT (p->header.prevsize > 0) ;
+ }
+
+ ASSERT (p->header.size != 0) ;
+ s = prevsize >= 0 ? prevsize : -prevsize ;
+ ASSERT (p->header.prevsize == s) ;
+ /* no adjacent free blocks */
+ ASSERT (p->header.size > 0 || prevsize > 0) ;
+ if (Numeric->ibig != EMPTY)
+ {
+ if (p == Numeric->Memory + Numeric->ibig)
+ {
+ ASSERT (p->header.size < 0) ;
+ DEBUG8 ((" <===== Numeric->ibig")) ;
+ found = TRUE ;
+ }
+ }
+ s = p->header.size ;
+ prevsize = s ;
+ s = s >= 0 ? s : -s ;
+ p = p + 1 + s ;
+ DEBUG8 (("\n")) ;
+ }
+
+ ASSERT (p == Numeric->Memory + Numeric->size) ;
+ ASSERT (IMPLIES (Numeric->ibig != EMPTY, found)) ;
+ DEBUG6 (("============================================= END OF MEMORY:\n"));
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_packed_memory =============================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_packed_memory
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ Unit *p, *p3 ;
+ Int prevsize, col, row, *Rows, *Cols, ncols, nrows, k, esize,
+ *Row_tuples, *Row_degree, *Col_tuples, *Col_degree ;
+ Entry *C ;
+ Element *ep ;
+
+ Col_degree = Numeric->Cperm ;
+ Row_degree = Numeric->Rperm ;
+ Row_tuples = Numeric->Uip ;
+ Col_tuples = Numeric->Lip ;
+
+ DEBUG6 (("============================================ PACKED MEMORY:\n")) ;
+ if (!Numeric || !Numeric->Memory)
+ {
+ DEBUG6 (("No memory space S allocated\n")) ;
+ return ;
+ }
+ DEBUG6 (("S: "ID"\n", (Int) Numeric)) ;
+ DEBUG6 (("S->ihead : "ID"\n", Numeric->ihead)) ;
+ DEBUG6 (("S->itail : "ID"\n", Numeric->itail)) ;
+ DEBUG6 (("S->size : "ID"\n", Numeric->size)) ;
+ DEBUG6 (("S->ngarbage : "ID"\n", Numeric->ngarbage)) ;
+ DEBUG6 (("S->nrealloc : "ID"\n", Numeric->nrealloc)) ;
+ DEBUG6 ((" in use at head : "ID"\n", Numeric->ihead)) ;
+ DEBUG6 ((" free space : "ID"\n",
+ Numeric->itail - Numeric->ihead)) ;
+ DEBUG6 ((" blocks in use at tail : "ID"\n",
+ Numeric->size - Numeric->itail)) ;
+ DEBUG6 ((" total in use : "ID"\n",
+ Numeric->size - (Numeric->itail - Numeric->ihead))) ;
+
+ ASSERT (0 <= Numeric->ihead) ;
+ ASSERT (Numeric->ihead <= Numeric->itail) ;
+ ASSERT (Numeric->itail <= Numeric->size) ;
+
+ for (row = 0 ; row < Work->n_row ; row++)
+ {
+ ASSERT (IMPLIES (NON_PIVOTAL_ROW (row), !Row_tuples [row])) ;
+ }
+ for (col = 0 ; col < Work->n_col ; col++)
+ {
+ ASSERT (IMPLIES (NON_PIVOTAL_COL (col), !Col_tuples [col])) ;
+ }
+
+ prevsize = 0 ;
+ p = Numeric->Memory + Numeric->itail ;
+ while (p < Numeric->Memory + Numeric->size)
+ {
+ DEBUG9 (("====================\n")) ;
+ DEBUG7 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID"\n",
+ p-Numeric->Memory, p+1-Numeric->Memory,
+ p->header.prevsize, p->header.size)) ;
+ ASSERT (p->header.size > 0) ;
+
+ if (p == Numeric->Memory + Numeric->itail)
+ {
+ ASSERT (p->header.prevsize == 0) ;
+ }
+ else
+ {
+ ASSERT (p->header.prevsize > 0) ;
+ }
+
+ ASSERT (p->header.prevsize == prevsize) ;
+ prevsize = p->header.size ;
+
+ if (p != Numeric->Memory + Numeric->size - 2)
+ {
+
+ p3 = p + 1 ;
+
+ /* this is a packed element */
+ GET_ELEMENT (ep, p3, Cols, Rows, ncols, nrows, C) ;
+ DEBUG9 (("ep "ID"\n nrows "ID" ncols "ID"\n",
+ (p+1)-Numeric->Memory, ep->nrows, ep->ncols)) ;
+ DEBUG9 (("rows:")) ;
+ for (k = 0 ; k < ep->nrows; k++)
+ {
+ row = Rows [k] ;
+ DEBUG9 ((" "ID, row)) ;
+ ASSERT (row >= 0 && row <= Work->n_row) ;
+ if ((k % 10) == 9) DEBUG9 (("\n")) ;
+ }
+ DEBUG9 (("\ncols:")) ;
+ for (k = 0 ; k < ep->ncols; k++)
+ {
+ col = Cols [k] ;
+ DEBUG9 ((" "ID, col)) ;
+ ASSERT (col >= 0 && col <= Work->n_col) ;
+ if ((k % 10) == 9) DEBUG9 (("\n")) ;
+ }
+ DEBUG9 (("\nvalues: ")) ;
+ if (UMF_debug >= 9)
+ {
+ UMF_dump_dense (C, ep->nrows, ep->nrows, ep->ncols) ;
+ }
+ esize = GET_ELEMENT_SIZE (ep->nrows, ep->ncols) ;
+ DEBUG9 (("esize: "ID"\n", esize)) ;
+ ASSERT (esize <= p->header.size) ;
+
+ }
+ else
+ {
+ /* this is the final marker block */
+ ASSERT (p->header.size == 1) ;
+ }
+ p = p + 1 + p->header.size ;
+ }
+
+ ASSERT (Numeric->ibig == EMPTY) ;
+ ASSERT (p == Numeric->Memory + Numeric->size) ;
+ DEBUG6 (("======================================END OF PACKED MEMORY:\n")) ;
+
+}
+
+/* ========================================================================== */
+/* === UMF_dump_col_matrix ================================================== */
+/* ========================================================================== */
+
+/* This code is the same for real or complex matrices. */
+
+GLOBAL void UMF_dump_col_matrix
+(
+ const double Ax [ ], /* Ax [0..nz-1]: real values, in column order */
+#ifdef COMPLEX
+ const double Az [ ], /* Az [0..nz-1]: imag values, in column order */
+#endif
+ const Int Ai [ ], /* Ai [0..nz-1]: row indices, in column order */
+ const Int Ap [ ], /* Ap [0..n_col]: column pointers */
+ Int n_row, /* number of rows of A */
+ Int n_col, /* number of columns of A */
+ Int nz /* number of entries */
+)
+{
+ Int col, p, p1, p2, row ;
+ if (!Ai || !Ap) return ;
+ DEBUG6 (("============================================ COLUMN FORM:\n")) ;
+
+
+ ASSERT (n_col >= 0) ;
+ nz = Ap [n_col] ;
+ DEBUG2 (("UMF_dump_col: nz "ID"\n", nz)) ;
+ DEBUG2 (("n_row "ID" & "ID"\n", n_row, &n_row)) ;
+ DEBUG2 (("n_col "ID" & "ID"\n", n_col, &n_col)) ;
+ DEBUG2 (("Ap & "ID" to & "ID"\n", Ap, Ap + (n_col+1) - 1)) ;
+ DEBUG2 (("Ai & "ID" to & "ID"\n", Ai, Ai + (nz) - 1)) ;
+ if (Ax) DEBUG2 (("Ax & "ID" to & "ID"\n", Ax, Ax + (nz) - 1)) ;
+
+#ifdef COMPLEX
+ if (Az) DEBUG2 (("Az & "ID" to & "ID"\n", Az, Az + (nz) - 1)) ;
+#endif
+
+ DEBUG6 ((" n_row = "ID", n_col ="ID" nz = "ID" Ap [0] "ID", Ap [n] "ID"\n",
+ n_row, n_col, nz, Ap [0], Ap [n_col])) ;
+ ASSERT (Ap [0] == 0) ;
+ ASSERT (Ap [n_col] == nz) ;
+ for (col = 0 ; col < n_col ; col++)
+ {
+ p1 = Ap [col] ;
+ p2 = Ap [col+1] ;
+ DEBUG6 (("col: "ID", length "ID"\n", col, p2 - p1)) ;
+ ASSERT (p2 >= p1) ;
+ for (p = p1 ; p < p2 ; p++)
+ {
+ row = Ai [p] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ DEBUG6 (("\t"ID" ", row)) ;
+ if (Ax)
+ {
+#ifdef COMPLEX
+ if (Az)
+ {
+ DEBUG6 ((" (%e+%ei) ", Ax [p], Az [p])) ;
+ }
+ else
+ {
+ DEBUG6 ((" %e", Ax [p])) ;
+ }
+#else
+ DEBUG6 ((" %e", Ax [p])) ;
+#endif
+ }
+ DEBUG6 (("\n")) ;
+ }
+ }
+ DEBUG6 (("========================================== COLUMN FORM done\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_chain ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_chain
+(
+ Int frontid,
+ Int Front_parent [ ],
+ Int Front_npivcol [ ],
+ Int Front_nrows [ ],
+ Int Front_ncols [ ],
+ Int nfr
+)
+{
+ Int i, len = 0 ;
+
+ /* print a list of contiguous parents */
+ i = frontid ;
+ ASSERT (Front_parent [i] == EMPTY ||
+ (Front_parent [i] > i && Front_parent [i] < nfr)) ;
+
+ len++ ;
+ DEBUG3 (("Chain:\n "ID" ["ID","ID"]("ID"-by-"ID")\n", i,
+ Front_npivcol [i],
+ MIN (Front_npivcol [i], Front_nrows [i]),
+ Front_nrows [i],
+ Front_ncols [i])) ;
+
+ for (i = frontid ; i < nfr ; i++)
+ {
+ ASSERT (Front_parent [i] == EMPTY ||
+ (Front_parent [i] > i && Front_parent [i] < nfr)) ;
+ if (Front_parent [i] == i+1)
+ {
+ len++ ;
+ DEBUG3 (("\t"ID" ["ID","ID"]("ID"-by-"ID")\n", i+1,
+ Front_npivcol [i+1],
+ MIN (Front_npivcol [i+1], Front_nrows [i+1]),
+ Front_nrows [i+1],
+ Front_ncols [i+1])) ;
+ }
+ else
+ {
+ DEBUG2 (("Length of chain: "ID"\n", len)) ;
+ return ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_start ======================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_start
+(
+ void
+)
+{
+ FILE *ff ;
+
+ /* get the debug print level from the "debug.umf" file, if it exists */
+ UMF_debug = 0 ;
+ ff = fopen ("debug.umf", "r") ;
+ if (ff)
+ {
+ (void) fscanf (ff, ID, &UMF_debug) ;
+ (void) fclose (ff) ;
+ }
+
+ DEBUG0 (("umfpack: debug version (SLOW!) ")) ;
+
+ DEBUG0 ((" BLAS: ")) ;
+
+#if defined (USE_NO_BLAS)
+ DEBUG0 (("none.")) ;
+#elif defined (USE_C_BLAS)
+ DEBUG0 (("C-BLAS.")) ;
+#elif defined (USE_MATLAB_BLAS)
+ DEBUG0 (("built-in MATLAB BLAS.")) ;
+#elif defined (USE_SUNPERF_BLAS)
+ DEBUG0 (("Sun Performance Library BLAS.")) ;
+#elif defined (USE_SCSL_BLAS)
+ DEBUG0 (("SGI SCSL BLAS.")) ;
+#elif defined (USE_FORTRAN_BLAS)
+ DEBUG0 (("Fortran BLAS.")) ;
+#endif
+
+ DEBUG0 ((" MATLAB: ")) ;
+#ifdef MATLAB_MEX_FILE
+ DEBUG0 (("mexFunction.\n")) ;
+#else
+#ifdef MATHWORKS
+ DEBUG0 (("yes (uses MathWorks internal ut* routines).\n")) ;
+#else
+ DEBUG0 (("no.\n")) ;
+#endif
+#endif
+
+ UMF_gprob = -1.0 ;
+ ff = fopen ("gprob.umf", "r") ;
+ if (ff)
+ {
+ (void) fscanf (ff, "%lg", &UMF_gprob) ;
+ (void) fclose (ff) ;
+ }
+
+ if (UMF_gprob > 1.0) UMF_gprob = 1.0 ;
+ DEBUG1 (("factor: UMF_gprob: %e UMF_debug "ID"\n", UMF_gprob, UMF_debug)) ;
+
+ DEBUG2 (("sizeof: (bytes / int / Units) \n")) ;
+ DEBUG2 (("sizeof (Int) %u %u %u\n",
+ sizeof (Int), sizeof (Int) / sizeof (int), UNITS (Int, 1) )) ;
+ DEBUG2 (("sizeof (int) %u %u %u\n",
+ sizeof (int), sizeof (int) / sizeof (int), UNITS (int, 1) )) ;
+ DEBUG2 (("sizeof (size_t) %u %u %u\n",
+ sizeof (size_t), sizeof (size_t) / sizeof (size_t), UNITS (size_t, 1) )) ;
+ DEBUG2 (("sizeof (long) %u %u %u\n",
+ sizeof (long), sizeof (long) / sizeof (long), UNITS (long, 1) )) ;
+ DEBUG2 (("sizeof (double) %u %u %u\n",
+ sizeof (double), sizeof (double) / sizeof (int), UNITS (double, 1) )) ;
+ DEBUG2 (("sizeof (Unit) %u %u %u\n",
+ sizeof (Unit), sizeof (Unit) / sizeof (int), UNITS (Unit, 1) )) ;
+ DEBUG2 (("sizeof (Entry) %u %u %u\n",
+ sizeof (Entry), sizeof (Entry) / sizeof (int), UNITS (Entry, 1) )) ;
+ DEBUG2 (("sizeof (Tuple) %u %u %u\n",
+ sizeof (Tuple), sizeof (Tuple) / sizeof (int), UNITS (Tuple, 1) )) ;
+ DEBUG2 (("sizeof (Tuple *) %u %u %u\n",
+ sizeof (Tuple *), sizeof (Tuple *) / sizeof (int), UNITS (Tuple *, 1) )) ;
+ DEBUG2 (("sizeof (Element) %u %u %u\n",
+ sizeof (Element), sizeof (Element) / sizeof (int), UNITS (Element, 1) )) ;
+ DEBUG2 (("sizeof (Element *) %u %u %u\n",
+ sizeof (Element *), sizeof (Element *) / sizeof (int),
+ UNITS (Element *, 1) )) ;
+ DEBUG2 (("sizeof (WorkType) %u %u %u\n",
+ sizeof (WorkType), sizeof (WorkType) / sizeof (int),
+ UNITS (WorkType, 1) )) ;
+ DEBUG2 (("sizeof (NumericType) %u %u %u\n",
+ sizeof (NumericType), sizeof (NumericType) / sizeof (int),
+ UNITS (NumericType, 1) )) ;
+ DEBUG2 (("sizeof (SymbolicType) %u %u %u\n",
+ sizeof (SymbolicType), sizeof (SymbolicType) / sizeof (int),
+ UNITS (SymbolicType, 1) )) ;
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_dump_rowmerge ==================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_rowmerge
+(
+ NumericType *Numeric,
+ SymbolicType *Symbolic,
+ WorkType *Work
+)
+{
+ Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1, row2,
+ fleftmost, nfr, n_row, *Row_degree, i, frontid, row ;
+
+ nfr = Symbolic->nfr ;
+ DEBUG3 (("\n================== Row merge sets: nfr "ID"\n", nfr)) ;
+ Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+ Front_1strow = Symbolic->Front_1strow ;
+ Front_new1strow = Work->Front_new1strow ;
+ n_row = Symbolic->n_row ;
+ Row_degree = Numeric->Rperm ;
+ frontid = Work->frontid ;
+
+ for (i = frontid ; i <= nfr ; i++)
+ {
+ DEBUG3 (("----------------------\n")) ;
+ if (i == nfr) DEBUG3 (("Dummy: ")) ;
+ DEBUG3 (("Front "ID" 1strow "ID" new1strow "ID" leftmostdesc "ID,
+ i, Front_1strow [i], Front_new1strow [i], Front_leftmostdesc [i])) ;
+ DEBUG3 ((" parent "ID" pivcol\n", Symbolic->Front_parent [i],
+ Symbolic->Front_npivcol [i])) ;
+
+ if (i == nfr)
+ {
+ fleftmost = -1 ;
+ row1 = Front_new1strow [i] ;
+ row2 = n_row-1 ;
+ }
+ else
+ {
+ fleftmost = Front_leftmostdesc [i] ;
+ row1 = Front_new1strow [fleftmost] ;
+ row2 = Front_1strow [i+1] - 1 ;
+ }
+ DEBUG3 (("Leftmost: "ID" Rows ["ID" to "ID"], search ["ID" to "ID"]\n",
+ fleftmost, Front_1strow [i], row2, row1, row2)) ;
+
+ for (row = row1 ; row <= row2 ; row++)
+ {
+ ASSERT (row >= 0 && row < n_row) ;
+ DEBUG3 ((" Row "ID" live: "ID"\n", row, NON_PIVOTAL_ROW (row))) ;
+ }
+ }
+}
+
+#endif /* NDEBUG */
diff --git a/src/sparse-matrix/umfpack/umf_extend_front.c b/src/sparse-matrix/umfpack/umf_extend_front.c
new file mode 100644
index 0000000..99335f0
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_extend_front.c
@@ -0,0 +1,673 @@
+/* ========================================================================== */
+/* === UMF_extend_front ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Called by kernel. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_extend_front
+(
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Entry *Fx, *Flast, *Fd, *Fs, *Fcol, *Frow, temp, *Flrow, *Fu ;
+ Int j, i, fnpiv, *Frows, row, col, i2, *Wrow, *Wcol,
+ *Frpos, *Fcpos, *Fcols, pivcol, pivrow, fnrows_extended, rrdeg, ccdeg,
+ fncols_extended, fnrows_max, fncols_max, fnrows, fncols,
+ fspos, fdpos, fs, j2, j3, col2, row2, fncols_orig ;
+#ifndef NDEBUG
+ Int debug_ok ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ Frows = Work->Frows ;
+ Frpos = Work->Frpos ;
+ Fcols = Work->Fcols ;
+ Fcpos = Work->Fcpos ;
+ Fx = Work->Fx ;
+ pivcol = Work->pivcol ;
+ pivrow = Work->pivrow ;
+ fnrows_max = Work->fnrows_max ;
+ fncols_max = Work->fncols_max ;
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ fncols_orig = fncols ;
+ rrdeg = Work->rrdeg ;
+ ccdeg = Work->ccdeg ;
+
+#ifndef NDEBUG
+ DEBUG2 (("EXTEND FRONT\n")) ;
+ if (fncols == 0 || fnrows == 0)
+ {
+ DEBUG2 (("Extending empty front "ID" "ID"\n", fnrows,fncols)) ;
+ }
+ DEBUG6 (("Pivot row, before shift and extension: "ID"\n", fncols)) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ DEBUG7 ((" "ID" "ID" "ID" "ID"\n",
+ j, Fcols [j], Fcpos [Fcols [j]], j < fncols)) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnrows_max) ;
+ }
+ DEBUG6 (("Pivot col, before shift and extension: "ID"\n", fnrows)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG7 ((" "ID" "ID" "ID" "ID"\n",
+ i, Frows [i], Frpos [Frows [i]], i < fnrows)) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+ if (Work->pivcol_in_front)
+ {
+ DEBUG6 (("Extended part of pivot col, before shift/extension: "ID"\n",
+ fnrows)) ;
+ for (i = fnrows ; i < fnrows + ccdeg ; i++)
+ {
+ DEBUG7 ((" "ID" "ID" "ID" "ID"\n",
+ i, Frows [i], Frpos [Frows [i]], i < fnrows)) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+ }
+ DEBUG2 (("Work->fnpiv "ID"\n", Work->fnpiv)) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* pivot column already updated */
+ /* ---------------------------------------------------------------------- */
+
+ fnpiv = Work->fnpiv ;
+
+ /* ====================================================================== */
+ /* === Shift pivot row and column ======================================= */
+ /* ====================================================================== */
+
+ /* ---------------------------------------------------------------------- */
+ /* move the pivot column into place */
+ /* ---------------------------------------------------------------------- */
+
+ fdpos = (fncols_max - fnpiv - 1) * fnrows_max ;
+ Fd = Fx + fdpos ; /* Fd: destination of pivot column */
+
+#ifndef NDEBUG
+ /*
+ DEBUG7 (("Complete frontal matrix prior to pivcol swap (incl unused):\n")) ;
+ UMF_dump_dense (Fx, fnrows_max, fnrows_max, fncols_max) ;
+ */
+#endif
+
+ if (Work->pivcol_in_front)
+ {
+
+ fspos = Fcpos [pivcol] ;
+ fs = fspos / fnrows_max ;
+
+ /* Fs: current position of pivot column */
+ Fs = Fx + fspos ;
+
+ /* Flast: position of last column in front */
+ Flast = Fx + (fncols - 1) * fnrows_max ;
+
+ /* ------------------------------------------------------------------ */
+ /* pivot column is in current front - shift into place */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG6 (("Swap/shift pivot column in front\n")) ;
+ DEBUG6 (("fspos: "ID" flpos: "ID" fdpos: "ID"\n",
+ fspos, (fncols - 1) * fnrows_max, fdpos)) ;
+
+ if (Flast != Fd)
+ {
+ if (Fs == Flast)
+ {
+ /* ---------------------------------------------------------- */
+ /* move Fs => Fd */
+ /* ---------------------------------------------------------- */
+
+ DEBUG6 (("col case 1\n")) ;
+
+ /* column of the contribution block: */
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Fd [i] = Fs [i] ;
+ }
+
+#ifndef NDEBUG
+ /* column of the U2 block */
+ for (i = fnrows_max - fnpiv ; i < fnrows_max ; i++)
+ {
+ ASSERT (IS_ZERO (Fs [i])) ;
+ }
+#endif
+
+ }
+ else
+ {
+ /* ---------------------------------------------------------- */
+ /* move Fs => Fd */
+ /* move Flast => Fs */
+ /* ---------------------------------------------------------- */
+
+ DEBUG6 (("col case 2\n")) ;
+
+ /* column of the contribution block: */
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Fd [i] = Fs [i] ;
+ Fs [i] = Flast [i] ;
+ }
+ /* column of the U2 block */
+ for (i = fnrows_max - fnpiv ; i < fnrows_max ; i++)
+ {
+ ASSERT (IS_ZERO (Fs [i])) ;
+ Fs [i] = Flast [i] ;
+ }
+ }
+ }
+ else if (Fs != Fd)
+ {
+ /* -------------------------------------------------------------- */
+ /* swap Fs <=> Fd */
+ /* -------------------------------------------------------------- */
+
+ DEBUG6 (("col case 3\n")) ;
+
+ /* column of the contribution block: */
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ temp = Fd [i] ;
+ Fd [i] = Fs [i] ;
+ Fs [i] = temp ;
+ }
+ /* column of the U2 block */
+ for (i = fnrows_max - fnpiv ; i < fnrows_max ; i++)
+ {
+ ASSERT (IS_ZERO (Fs [i])) ;
+ Fs [i] = Fd [i] ;
+ }
+ }
+
+ /* move column Flast to Fs in the Fcols pattern */
+ col2 = Fcols [fncols - 1] ;
+ Fcols [fs] = col2 ;
+ Fcpos [col2] = fspos ;
+
+ /* one less column in the contribution block */
+ fncols = --(Work->fncols) ;
+
+ }
+ else
+ {
+ /* ------------------------------------------------------------------ */
+ /* pivot column is not in front - tack onto L block */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG6 (("Pivot column not in front\ncol case 5\n")) ;
+
+ /* column of L */
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ CLEAR (Fd [i]) ;
+ }
+ /* column of U2 */
+ for (i = fnrows_max - fnpiv ; i < fnrows_max ; i++)
+ {
+ CLEAR (Fd [i]) ;
+ }
+
+ }
+
+ /* move pivot column to Fd */
+ Fcpos [pivcol] = fdpos ;
+
+ /* scan starts at the first new column in Fcols */
+ /* also scan the pivot column if it was not in the front */
+ Work->fscan_col = fncols ;
+
+#ifndef NDEBUG
+ DEBUG6 (("Pivot row, after shift but before extension: "ID"\n", fncols)) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ DEBUG7 ((" "ID" "ID" "ID" "ID"\n",
+ j, Fcols [j], Fcpos [Fcols [j]], j < fncols)) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnrows_max) ;
+ }
+ /*
+ DEBUG7 (("Complete frontal matrix after pivot col swap (incl unused):\n")) ;
+ UMF_dump_dense (Fx, fnrows_max, fnrows_max, fncols_max) ;
+ */
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* move pivot row into place */
+ /* ---------------------------------------------------------------------- */
+
+ fdpos = fnrows_max - fnpiv - 1 ;
+ Fd = Fx + fdpos ; /* Fd: destination of pivot row */
+
+ if (Work->pivrow_in_front)
+ {
+
+ fspos = Frpos [pivrow] ;
+
+ /* Fs: current position of pivot column in front */
+ Fs = Fx + fspos ;
+
+ /* Flast: position of last row in front */
+ Flast = Fx + (fnrows - 1) ;
+
+ /* ------------------------------------------------------------------ */
+ /* pivot row is in current front - shift into place */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG6 (("Swap/shift pivot row in front:\n")) ;
+ DEBUG6 (("fspos: "ID" flpos: "ID" fdpos: "ID"\n",
+ fspos, fnrows-1, fdpos)) ;
+
+ if (Flast != Fd)
+ {
+ if (Fs == Flast)
+ {
+ /* ---------------------------------------------------------- */
+ /* move Fs => Fd */
+ /* ---------------------------------------------------------- */
+
+ DEBUG6 (("row case 1\n")) ;
+
+ /* row of the contribution block: */
+ j2 = fncols * fnrows_max ;
+ for (j = 0 ; j < j2 ; j += fnrows_max)
+ {
+ Fd [j] = Fs [j] ;
+ }
+
+ /* row of the L2 block: */
+ j2 = fncols_max * fnrows_max ;
+ j = (fncols_max - fnpiv - 1) * fnrows_max ;
+ for ( ; j < j2 ; j += fnrows_max)
+ {
+ Fd [j] = Fs [j] ;
+ }
+
+ }
+ else
+ {
+
+ /* ---------------------------------------------------------- */
+ /* move Fs => Fd */
+ /* move Flast => Fs */
+ /* ---------------------------------------------------------- */
+
+ DEBUG6 (("row case 2\n")) ;
+
+ /* row of the contribution block: */
+ j2 = fncols * fnrows_max ;
+ for (j = 0 ; j < j2 ; j += fnrows_max)
+ {
+ Fd [j] = Fs [j] ;
+ Fs [j] = Flast [j] ;
+ }
+ /* row of the L2 block: */
+ j2 = fncols_max * fnrows_max ;
+ j = (fncols_max - fnpiv - 1) * fnrows_max ;
+ for ( ; j < j2 ; j += fnrows_max)
+ {
+ Fd [j] = Fs [j] ;
+ Fs [j] = Flast [j] ;
+ }
+ }
+ }
+ else if (Fs != Fd)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* swap Fs <=> Fd */
+ /* -------------------------------------------------------------- */
+
+ DEBUG6 (("row case 3\n")) ;
+
+ /* row of the contribution block: */
+ j2 = fncols * fnrows_max ;
+ for (j = 0 ; j < j2 ; j += fnrows_max)
+ {
+ temp = Fd [j] ;
+ Fd [j] = Fs [j] ;
+ Fs [j] = temp ;
+ }
+ /* row of the L2 block: */
+ j2 = fncols_max * fnrows_max ;
+ j = (fncols_max - fnpiv - 1) * fnrows_max ;
+ for ( ; j < j2 ; j += fnrows_max)
+ {
+ temp = Fd [j] ;
+ Fd [j] = Fs [j] ;
+ Fs [j] = temp ;
+ }
+ }
+
+ /* move row Flast to Fs in the Frows pattern */
+ row2 = Frows [fnrows-1] ;
+ Frows [fspos] = row2 ;
+ Frpos [row2] = fspos ;
+
+
+ if (Work->pivcol_in_front && ccdeg > 0)
+ {
+
+ /* move row Fe to Flast in the extended Frows pattern */
+ row2 = Frows [fnrows + ccdeg - 1] ;
+ Frows [fnrows-1] = row2 ;
+ Frpos [row2] = fnrows-1 ;
+ }
+
+ /* one less row in the contribution block */
+ fnrows = --(Work->fnrows) ;
+
+ /* ------------------------------------------------------------------ */
+ /* update pivot row */
+ /* ------------------------------------------------------------------ */
+
+ if (fnpiv > 0 && fncols > 0)
+ {
+ DEBUG6 (("Update pivot row (but not pivot entry itself):\n")) ;
+ Fu = Fd + 1 ;
+ Flrow = Fd + (fncols_max - fnpiv) * fnrows_max ;
+
+#ifdef USE_NO_BLAS
+
+ /* no BLAS available - use plain C code instead */
+ j2 = 0 ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ i2 = 0 ;
+ for (i = 0 ; i < fnpiv ; i++)
+ {
+ /* Fd [j2] -= Fu [i+j*fnrows_max] * Flrow [i2] ; */
+ MULT_SUB (Fd [j2], Fu [i+j*fnrows_max], Flrow [i2]) ;
+ i2 += fnrows_max ;
+ }
+ j2 += fnrows_max ;
+ }
+
+#else
+
+ BLAS_GEMV_ROW (fnpiv, fncols, Fu, Flrow, Fd, fnrows_max) ;
+
+#endif /* USE_NO_BLAS */
+
+ }
+
+ }
+ else
+ {
+ /* ------------------------------------------------------------------ */
+ /* pivot row is not in front - tack onto U block */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG6 (("Pivot row not in current front\nrow case 5\n")) ;
+
+ /* row of U */
+ j2 = fncols * fnrows_max ;
+ for (j = 0 ; j < j2 ; j += fnrows_max)
+ {
+ CLEAR (Fd [j]) ;
+ }
+ /* row of L2 */
+ j2 = fncols_max * fnrows_max ;
+ j = (fncols_max - fnpiv - 1) * fnrows_max ;
+ for ( ; j < j2 ; j += fnrows_max)
+ {
+ CLEAR (Fd [j]) ;
+ }
+
+ }
+
+ /* move pivot row to Fd */
+ Frpos [pivrow] = fdpos ;
+
+ /* scan1 starts at the first new row in Frows */
+ /* also scan the pivot row if it was not in the front */
+ Work->fscan_row = fnrows ;
+
+#ifndef NDEBUG
+ debug_ok = TRUE ;
+ DEBUG6 (("Pivot col, before shift but before extension: "ID"\n", fnrows)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG7 ((" "ID" "ID" "ID" "ID"\n",
+ i, Frows [i], Frpos [Frows [i]], i < fnrows)) ;
+ debug_ok = debug_ok && (Frpos [Frows [i]] == i) ;
+ }
+ ASSERT (debug_ok) ;
+#endif
+
+ /* ====================================================================== */
+ /* === EXTEND PATTERN OF FRONT ========================================== */
+ /* ====================================================================== */
+
+ /* ---------------------------------------------------------------------- */
+ /* extend row pattern of the front with the new pivot column extension */
+ /* ---------------------------------------------------------------------- */
+
+ fnrows_extended = fnrows ;
+ fncols_extended = fncols ;
+
+ if (Work->pivcol_in_front)
+ {
+ /* extended pattern and position already in Frows and Frpos */
+ fnrows_extended += ccdeg ;
+
+#ifndef NDEBUG
+ debug_ok = TRUE ;
+ for (i = fnrows ; i < fnrows + ccdeg ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG2 ((" row:: "ID" (ext)\n", row)) ;
+ debug_ok = debug_ok && (Frpos [row] == i) && (row != pivrow) ;
+ }
+ ASSERT (debug_ok) ;
+#endif
+
+ }
+ else
+ {
+ /* extended pattern is in Wcol, not yet in the front */
+ Wcol = Work->Wcol ;
+ ASSERT (Wcol == Work->Wm) ;
+ for (i = 0 ; i < ccdeg ; i++)
+ {
+ row = Wcol [i] ;
+ DEBUG2 ((" row:: "ID" (ext)\n", row)) ;
+ ASSERT (Frpos [row] == EMPTY);
+ ASSERT (row != pivrow) ;
+ Frows [fnrows_extended] = row ;
+ Frpos [row] = fnrows_extended ;
+ fnrows_extended++ ;
+ }
+ }
+
+ ASSERT (fnpiv + fnrows_extended <= fnrows_max) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* extend the column pattern of the front with the new pivot row */
+ /* ---------------------------------------------------------------------- */
+
+ if (Work->pivrow_in_front)
+ {
+ if (Work->pivcol_in_front)
+ {
+
+ /* fill in the hole made when the pivot column was removed */
+ if (rrdeg > fncols_orig)
+ {
+ Fcols [fncols] = Fcols [--rrdeg] ;
+ fncols_extended = rrdeg ;
+ for (i = fncols ; i < rrdeg ; i++)
+ {
+#ifndef NDEBUG
+ col = Fcols [i] ;
+ ASSERT (col != pivcol) ;
+ DEBUG2 ((" col:: "ID" (ext)\n", col)) ;
+ ASSERT (Fcpos [col] < 0) ;
+#endif
+ Fcpos [Fcols [i]] = i * fnrows_max ;
+ }
+ }
+ }
+ else
+ {
+ Wrow = Work->Wrow ;
+ for (i = fncols_orig ; i < rrdeg ; i++)
+ {
+ col = Wrow [i] ;
+ if (col != pivcol)
+ {
+ DEBUG2 ((" col:: "ID" (ext)\n", col)) ;
+ ASSERT (Fcpos [col] < 0) ;
+ Fcols [fncols_extended] = col ;
+ Fcpos [col] = fncols_extended * fnrows_max ;
+ fncols_extended++ ;
+ }
+ }
+ }
+ }
+ else
+ {
+ Wrow = Work->Wrow ;
+ for (i = 0 ; i < rrdeg ; i++)
+ {
+ col = Wrow [i] ;
+ if (col != pivcol && Fcpos [col] < 0)
+ {
+ DEBUG2 ((" col:: "ID" (ext)\n", col)) ;
+ Fcols [fncols_extended] = col ;
+ Fcpos [col] = fncols_extended * fnrows_max ;
+ fncols_extended++ ;
+ }
+ }
+ }
+
+
+#ifndef NDEBUG
+ ASSERT (fnpiv + fncols_extended <= fncols_max) ;
+ DEBUG6 (("Pivot row, after shift and extension: "ID" "ID"\n",
+ fncols,fncols_extended)) ;
+ for (j = 0 ; j < fncols_extended ; j++)
+ {
+ DEBUG7 ((" "ID" "ID" "ID" "ID"\n",
+ j, Fcols [j], Fcpos [Fcols [j]], j < fncols)) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnrows_max) ;
+ }
+ DEBUG6 (("Pivot col, after shift and extension: "ID" "ID"\n",
+ fnrows,fnrows_extended)) ;
+ for (i = 0 ; i < fnrows_extended ; i++)
+ {
+ DEBUG7 ((" "ID" "ID" "ID" "ID"\n",
+ i, Frows [i], Frpos [Frows [i]], i < fnrows)) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+ /*
+ DEBUG7 (("Complete frontal matrix after all swaps (incl unused):\n")) ;
+ UMF_dump_dense (Fx, fnrows_max, fnrows_max, fncols_max) ;
+ */
+#endif
+
+ /* ====================================================================== */
+ /* Prepare for degree update and next local pivot search */
+ /* ====================================================================== */
+
+#ifndef NDEBUG
+ DEBUG6 (("JUST BEFORE SCAN3A/4A:\nPivot row pattern:\n")) ;
+ for (j = 0 ; j < fncols_extended ; j++)
+ {
+ DEBUG7 ((ID" "ID" "ID" "ID"\n",
+ j, Fcols [j], Fcpos [Fcols [j]], j < fncols)) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnrows_max) ;
+ }
+ DEBUG6 (("Pivot col pattern:\n")) ;
+ for (i = 0 ; i < fnrows_extended ; i++)
+ {
+ DEBUG7 ((ID" "ID" "ID" "ID"\n",
+ i, Frows [i], Frpos [Frows [i]], i < fnrows)) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* Finished with step fnpiv (except for assembly and scale of pivot col) */
+ /* ---------------------------------------------------------------------- */
+
+ fnpiv = ++(Work->fnpiv) ;
+
+#ifndef NDEBUG
+ DEBUG6 (("EXT: pivot row pattern: len="ID"\n", fncols_extended)) ;
+ for (j = 0 ; j < fncols_extended ; j++) DEBUG7 ((ID"\n", Fcols [j])) ;
+ DEBUG6 (("EXT: pivot col pattern: len="ID"\n", fnrows_extended)) ;
+ for (j = 0 ; j < fnrows_extended ; j++) DEBUG7 ((ID"\n", Frows [j])) ;
+#endif
+
+ /* ====================================================================== */
+ /* === EXTEND NUMERICAL FRONT =========================================== */
+ /* ====================================================================== */
+
+ /* ---------------------------------------------------------------------- */
+ /* Zero the newly extended frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ Fcol = Fx + fncols * fnrows_max ;
+ i2 = fnrows_max - fnpiv ;
+ for (j = fncols ; j < fncols_extended ; j++)
+ {
+ /* zero the new columns in the contribution block: */
+ for (i = 0 ; i < fnrows_extended ; i++)
+ {
+ CLEAR (Fcol [i]) ;
+ }
+ /* zero the new columns in U block: */
+ for (i = i2 ; i < fnrows_max ; i++)
+ {
+ CLEAR (Fcol [i]) ;
+ }
+ Fcol += fnrows_max ;
+ }
+
+ Frow = Fx + fnrows ;
+ j3 = fncols_max - fnpiv ;
+ for (i = fnrows ; i < fnrows_extended ; i++)
+ {
+ /* zero the new rows in the contribution block: */
+ for (j = 0 ; j < fncols ; j++)
+ {
+ CLEAR (Frow [j * fnrows_max]) ;
+ }
+ /* zero the new rows in L block: */
+ for (j = j3 ; j < fncols_max ; j++)
+ {
+ CLEAR (Frow [j * fnrows_max]) ;
+ }
+ Frow++ ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* finalize extended row and column pattern of the frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ Work->fnrows = fnrows_extended ;
+ Work->fncols = fncols_extended ;
+
+ Work->scan_pivcol = !Work->pivcol_in_front ;
+ Work->scan_pivrow = !Work->pivrow_in_front ;
+
+}
diff --git a/src/sparse-matrix/umfpack/umf_free.c b/src/sparse-matrix/umfpack/umf_free.c
new file mode 100644
index 0000000..df8cf4b
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_free.c
@@ -0,0 +1,45 @@
+/* ========================================================================== */
+/* === UMF_free ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Free a block previously allocated by UMF_malloc and return NULL.
+ Usage is p = UMF_free (p), to ensure that we don't free it twice.
+ Also maintains the UMFPACK malloc count.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+#include "umf_malloc.h"
+#endif
+
+GLOBAL void *UMF_free
+(
+ void *p
+)
+{
+ if (p)
+ {
+
+ /* see umf_config.h for the memory allocator selection */
+ FREE (p) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+ /* One more object has been free'd. Keep track of the count. */
+ /* (purely for sanity checks). */
+ UMF_malloc_count-- ;
+#endif
+
+ }
+
+ return ((void *) NULL) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_garbage_collection.c b/src/sparse-matrix/umfpack/umf_garbage_collection.c
new file mode 100644
index 0000000..0ffe43c
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_garbage_collection.c
@@ -0,0 +1,403 @@
+/* ========================================================================== */
+/* === UMF_garbage_collection =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Compress the elements at the tail of Numeric->Memory, and delete the tuples.
+ Elements are renumbered. The new numbering space is compressed, and
+ in the order of element creation (original elements of A first, followed
+ by the new elements in the order that they were formed).
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_garbage_collection
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int size, e, n_row, n_col, nrows, ncols, nrowsleft, ncolsleft, prevsize,
+ csize, size2, i2, j2, i, j, cdeg, rdeg, *E, row, col, n_inner,
+ *Rows, *Cols, *Rows2, *Cols2, nel, e2, *Row_tuples, *Col_tuples,
+ *Row_degree, *Col_degree ;
+ Entry *C, *C1, *C3, *C2 ;
+ Unit *psrc, *pdest, *p, *pnext ;
+ Element *epsrc, *epdest ;
+
+#ifndef NDEBUG
+ Int nmark ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
+ Row_tuples = Numeric->Uip ;
+ Col_tuples = Numeric->Lip ;
+ E = Work->E ;
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ n_inner = MIN (n_row, n_col) ;
+
+ /* note that the tuple lengths (Col_tlen and Row_tlen) are updated, but */
+ /* the tuple lists themselves are stale and are about to be destroyed */
+ /* and recreated. Do not attempt to scan them until they are recreated. */
+
+#ifndef NDEBUG
+ DEBUG0 (("::::GARBAGE COLLECTION::::\n")) ;
+ UMF_dump_memory (Numeric) ;
+#endif
+
+ Numeric->ngarbage++ ;
+
+ /* ---------------------------------------------------------------------- */
+ /* delete the tuple lists by marking the blocks as free */
+ /* ---------------------------------------------------------------------- */
+
+ /* do not modify Row_tlen and Col_tlen */
+ /* those are needed for UMF_build_tuples */
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row) && Row_tuples [row])
+ {
+ DEBUG2 (("row "ID" tuples "ID"\n", row, Row_tuples [row])) ;
+ p = Numeric->Memory + Row_tuples [row] - 1 ;
+ DEBUG2 (("Freeing tuple list row "ID", p-S "ID", size "ID"\n",
+ row, p-Numeric->Memory, p->header.size)) ;
+ ASSERT (p->header.size > 0) ;
+ ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+ ASSERT (p < Numeric->Memory + Numeric->size) ;
+ p->header.size = -p->header.size ;
+ Row_tuples [row] = 0 ;
+ }
+ }
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ if (NON_PIVOTAL_COL (col) && Col_tuples [col])
+ {
+ DEBUG2 (("col "ID" tuples "ID"\n", col, Col_tuples [col])) ;
+ p = Numeric->Memory + Col_tuples [col] - 1 ;
+ DEBUG2 (("Freeing tuple list col "ID", p-S "ID", size "ID"\n",
+ col, p-Numeric->Memory, p->header.size)) ;
+ ASSERT (p->header.size > 0) ;
+ ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+ ASSERT (p < Numeric->Memory + Numeric->size) ;
+ p->header.size = -p->header.size ;
+ Col_tuples [col] = 0 ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* mark the elements, and compress the name space */
+ /* ---------------------------------------------------------------------- */
+
+ nel = Work->nel ;
+
+#ifndef NDEBUG
+ nmark = 0 ;
+#endif
+
+ e2 = 0 ;
+ ASSERT (!E [0]) ; /* current version never uses element zero */
+
+ for (e = 0 ; e <= nel ; e++) /* for all elements in order of creation */
+ {
+ if (E [e])
+ {
+ psrc = Numeric->Memory + E [e] ;
+ psrc-- ; /* get the header of this block */
+ if (e > 0)
+ {
+ e2++ ; /* do not renumber element zero */
+ }
+ ASSERT (psrc->header.size > 0) ;
+ psrc->header.size = e2 ; /* store the new name in the header */
+#ifndef NDEBUG
+ nmark++ ;
+#endif
+ DEBUG7 ((ID":: Mark e "ID" at psrc-S "ID", new e "ID"\n",
+ nmark, e, psrc-Numeric->Memory, e2)) ;
+ E [e] = 0 ;
+
+ if (e == Work->nelorig)
+ {
+ /* this is the highest numbered original element */
+ Work->nelorig = e2 ;
+ }
+ if (e == Work->prior_element)
+ {
+ Work->prior_element = e2 ;
+ }
+ }
+ }
+
+ /* all 1..e2 are now in use (element zero may or may not be in use) */
+ Work->nel = e2 ;
+ nel = Work->nel ;
+
+#ifndef NDEBUG
+ for (e = 0 ; e <= n_col + n_inner ; e++)
+ {
+ ASSERT (!E [e]) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* compress the elements */
+ /* ---------------------------------------------------------------------- */
+
+ /* point to tail marker block of size 1 + header */
+ psrc = Numeric->Memory + Numeric->size - 2 ;
+ pdest = psrc ;
+ prevsize = psrc->header.prevsize ;
+ DEBUG7 (("Starting the compression:\n")) ;
+
+ while (prevsize > 0)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* move up to the next element above the current header, and */
+ /* get the element name and size */
+ /* (if it is an element, the name will be positive) */
+ /* ------------------------------------------------------------------ */
+
+ size = prevsize ;
+ psrc -= (size + 1) ;
+ e = psrc->header.size ;
+ prevsize = psrc->header.prevsize ;
+ /* top block at tail has prevsize of 0 */
+
+ /* a free block will have a negative size, so skip it */
+ /* otherwise, if size > 0, it holds the element name, not the size */
+
+ DEBUG8 (("psrc-S: "ID" prevsize: "ID" size: "ID, psrc-Numeric->Memory,
+ prevsize, size)) ;
+
+ if (e >= 0)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* this is an element, compress and move from psrc down to pdest */
+ /* -------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG7 (("\n")) ;
+ DEBUG7 ((ID":: Move element "ID": from: "ID" \n",
+ nmark, e, psrc-Numeric->Memory)) ;
+ nmark-- ;
+ ASSERT (e <= nel) ;
+ ASSERT (E [e] == 0) ;
+#endif
+
+ /* -------------------------------------------------------------- */
+ /* get the element scalars, and pointers to C, Rows, and Cols: */
+ /* -------------------------------------------------------------- */
+
+ p = psrc + 1 ;
+ GET_ELEMENT (epsrc, p, Cols, Rows, ncols, nrows, C) ;
+ nrowsleft = epsrc->nrowsleft ;
+ ncolsleft = epsrc->ncolsleft ;
+ cdeg = epsrc->cdeg ;
+ rdeg = epsrc->rdeg ;
+
+#ifndef NDEBUG
+ DEBUG7 ((" nrows "ID" nrowsleft "ID"\n", nrows, nrowsleft)) ;
+ DEBUG7 ((" ncols "ID" ncolsleft "ID"\n", ncols, ncolsleft)) ;
+ DEBUG8 ((" Rows:")) ;
+ for (i = 0 ; i < nrows ; i++) DEBUG8 ((" "ID, Rows [i])) ;
+ DEBUG8 (("\n Cols:")) ;
+ for (j = 0 ; j < ncols ; j++) DEBUG8 ((" "ID, Cols [j])) ;
+ DEBUG8 (("\n")) ;
+#endif
+
+ /* -------------------------------------------------------------- */
+ /* determine the layout of the new element */
+ /* -------------------------------------------------------------- */
+
+ csize = nrowsleft * ncolsleft ;
+ size2 = UNITS (Element, 1)
+ + UNITS (Int, nrowsleft + ncolsleft)
+ + UNITS (Entry, csize) ;
+
+ DEBUG7 (("Old size "ID" New size "ID"\n", size, size2)) ;
+
+ pnext = pdest ;
+ pnext->header.prevsize = size2 ;
+ pdest -= (size2 + 1) ;
+ DEBUG7 (("Move element from psrc-S "ID" to pdest-S "ID"\n",
+ psrc-Numeric->Memory, pdest-Numeric->Memory));
+
+ ASSERT (e > 0 || size == size2) ;
+ ASSERT (size2 <= size) ;
+ ASSERT (psrc + 1 + size <= pnext) ;
+ ASSERT (psrc <= pdest) ;
+
+ p = pdest + 1 ;
+ epdest = (Element *) p ;
+ p += UNITS (Element, 1) ;
+ Cols2 = (Int *) p ;
+ Rows2 = Cols2 + ncolsleft ;
+ p += UNITS (Int, nrowsleft + ncolsleft) ;
+ C2 = (Entry *) p ;
+
+ ASSERT (epdest >= epsrc) ;
+ ASSERT (Rows2 >= Rows) ;
+ ASSERT (Cols2 >= Cols) ;
+ ASSERT (C2 >= C) ;
+ ASSERT (p + UNITS (Entry, csize) == pnext) ;
+
+ /* -------------------------------------------------------------- */
+ /* move the contribution block */
+ /* -------------------------------------------------------------- */
+
+ /* overlap = psrc + size + 1 > pdest ; */
+
+ if (nrowsleft < nrows || ncolsleft < ncols)
+ {
+
+ /* ---------------------------------------------------------- */
+ /* compress contribution block in place prior to moving it */
+ /* ---------------------------------------------------------- */
+
+ DEBUG7 (("Compress C in place prior to move (incl unused):\n"));
+#ifndef NDEBUG
+ UMF_dump_dense (C, nrows, nrows, ncols) ;
+#endif
+ C1 = C ;
+ C3 = C ;
+ for (j = 0 ; j < ncols ; j++)
+ {
+ if (Cols [j] >= 0)
+ {
+ for (i = 0 ; i < nrows ; i++)
+ {
+ if (Rows [i] >= 0)
+ {
+ *C3++ = C1 [i] ;
+ }
+ }
+ }
+ C1 += nrows ;
+ }
+ ASSERT (C3-C == csize) ;
+ DEBUG8 (("Newly compressed contrib. block (all in use):\n")) ;
+#ifndef NDEBUG
+ UMF_dump_dense (C, nrowsleft, nrowsleft, ncolsleft) ;
+#endif
+ }
+
+ /* shift the contribution block down */
+ C += csize ;
+ C2 += csize ;
+ for (i = 0 ; i < csize ; i++)
+ {
+ *--C2 = *--C ;
+ }
+
+ /* -------------------------------------------------------------- */
+ /* move the row indices */
+ /* -------------------------------------------------------------- */
+
+ i2 = nrowsleft ;
+ for (i = nrows - 1 ; i >= 0 ; i--)
+ {
+ ASSERT (Rows2+i2 >= Rows+i) ;
+ if (Rows [i] >= 0)
+ {
+ Rows2 [--i2] = Rows [i] ;
+ }
+ }
+ ASSERT (i2 == 0) ;
+
+ j2 = ncolsleft ;
+ for (j = ncols - 1 ; j >= 0 ; j--)
+ {
+ ASSERT (Cols2+j2 >= Cols+j) ;
+ if (Cols [j] >= 0)
+ {
+ Cols2 [--j2] = Cols [j] ;
+ }
+ }
+ ASSERT (j2 == 0) ;
+
+ /* -------------------------------------------------------------- */
+ /* construct the new header */
+ /* -------------------------------------------------------------- */
+
+ /* E [0...e] is now valid */
+ E [e] = (pdest + 1) - Numeric->Memory ;
+ epdest = (Element *) (pdest + 1) ;
+
+ epdest->next = EMPTY ; /* destroys the son list */
+ epdest->ncols = ncolsleft ;
+ epdest->nrows = nrowsleft ;
+ epdest->ncolsleft = ncolsleft ;
+ epdest->nrowsleft = nrowsleft ;
+ epdest->rdeg = rdeg ;
+ epdest->cdeg = cdeg ;
+
+ ASSERT (size2 <= size) ;
+ pdest->header.prevsize = 0 ;
+ pdest->header.size = size2 ;
+
+ DEBUG7 (("After moving it:\n")) ;
+#ifndef NDEBUG
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+ }
+
+#ifndef NDEBUG
+ else
+ {
+ DEBUG8 ((" free\n")) ;
+ }
+#endif
+ DEBUG7 (("psrc "ID" tail "ID"\n",
+ psrc-Numeric->Memory, Numeric->itail)) ;
+ }
+
+ ASSERT (psrc == Numeric->Memory + Numeric->itail) ;
+ ASSERT (nmark == 0) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* final tail pointer */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (pdest >= Numeric->Memory + Numeric->itail) ;
+ Numeric->itail = pdest - Numeric->Memory ;
+ pdest->header.prevsize = 0 ;
+ Numeric->ibig = EMPTY ;
+ Numeric->tail_usage = Numeric->size - Numeric->itail ;
+
+ /* ---------------------------------------------------------------------- */
+ /* clear the unused E [nel+1 .. n_col + n_inner] */
+ /* ---------------------------------------------------------------------- */
+
+ for (e = nel+1 ; e <= n_col + n_inner ; e++)
+ {
+ E [e] = 0 ;
+ }
+
+#ifndef NDEBUG
+ UMF_dump_packed_memory (Numeric, Work) ;
+#endif
+
+ DEBUG8 (("::::GARBAGE COLLECTION DONE::::\n")) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_get_memory.c b/src/sparse-matrix/umfpack/umf_get_memory.c
new file mode 100644
index 0000000..af7a0c7
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_get_memory.c
@@ -0,0 +1,210 @@
+/* ========================================================================== */
+/* === UMF_get_memory ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Reallocate the workspace (Numeric->Memory) and shift elements downwards.
+ needunits: increase in size so that the free space is at least this many
+ Units (to which the tuple lengths is added).
+
+ Return TRUE if successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_garbage_collection.h"
+#include "umf_tuple_lengths.h"
+#include "umf_build_tuples.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_realloc.h"
+
+GLOBAL Int UMF_get_memory
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int needunits
+)
+{
+ Int i, minsize, newsize, newmem, costly, row, col, *Row_tlen, *Col_tlen,
+ n_row, n_col, *Row_degree, *Col_degree ;
+ Unit *mnew, *p ;
+ double nsize, bsize ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get and check parameters */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (Numeric) ;
+ ASSERT (Work) ;
+ ASSERT (Numeric->Memory) ;
+
+#ifndef NDEBUG
+ DEBUG1 (("::::GET MEMORY::::\n")) ;
+ UMF_dump_memory (Numeric) ;
+#endif
+
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */
+ Row_tlen = Numeric->Uilen ;
+ Col_tlen = Numeric->Lilen ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize the tuple list lengths */
+ /* ---------------------------------------------------------------------- */
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row))
+ {
+ Row_tlen [row] = 0 ;
+ }
+ }
+ for (col = 0 ; col < n_col ; col++)
+ {
+ if (NON_PIVOTAL_COL (col))
+ {
+ Col_tlen [col] = 0 ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* determine how much memory is needed for the tuples */
+ /* ---------------------------------------------------------------------- */
+
+ nsize = (double) needunits + 2 ;
+ needunits += UMF_tuple_lengths (Numeric, Work, &nsize) ;
+ needunits += 2 ; /* add 2, so that newmem >= 2 is true if realloc'd */
+
+ /* note: Col_tlen and Row_tlen are updated, but the tuple lists */
+ /* themselves are not. Do not attempt to scan the tuple lists. */
+ /* They are now stale, and are about to be destroyed and recreated. */
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the desired new size of memory */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG0 (("UMF_get_memory: needunits: "ID"\n", needunits)) ;
+
+ minsize = Numeric->size + needunits ;
+ nsize += (double) Numeric->size ;
+
+ bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
+
+ if (nsize > bsize) /* a double relop, but ignore NaN case */
+ {
+ return (FALSE) ; /* the minimum size is larger than Int_MAX */
+ }
+
+ newsize = (Int) (UMF_REALLOC_INCREASE * ((double) minsize)) ;
+ nsize *= UMF_REALLOC_INCREASE * (1.0 + MAX_EPSILON) ;
+
+ if (newsize < 0 || nsize > bsize)
+ {
+ newsize = (Int) bsize ; /* we cannot increase the size beyond bsize */
+ }
+ else
+ {
+ newsize = MAX (newsize, minsize) ;
+ }
+
+ DEBUG0 ((
+ "REALLOC MEMORY: needunits "ID" old size: "ID" new size: "ID" Units \n",
+ needunits, Numeric->size, newsize)) ;
+
+ /* Forget where the biggest free block is (we no longer need it) */
+ /* since garbage collection will occur shortly. */
+ Numeric->ibig = EMPTY ;
+
+ /* ---------------------------------------------------------------------- */
+ /* reallocate the memory, if possible, and make it bigger */
+ /* ---------------------------------------------------------------------- */
+
+ mnew = (Unit *) NULL ;
+ while (!mnew)
+ {
+ mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ;
+ if (!mnew)
+ {
+ if (newsize == minsize) /* last realloc attempt failed */
+ {
+ /* We failed to get the minimum. Just stick with the */
+ /* current allocation and hope that garbage collection */
+ /* can recover enough space. */
+ mnew = Numeric->Memory ; /* no new memory available */
+ newsize = Numeric->size ;
+ }
+ else
+ {
+ /* otherwise, reduce the request and keep trying */
+ newsize = (Int) (UMF_REALLOC_REDUCTION * ((double) newsize)) ;
+ newsize = MAX (minsize, newsize) ;
+ }
+ }
+ }
+ ASSERT (mnew) ;
+
+ /* see if realloc had to copy, rather than just extend memory */
+ costly = (mnew != Numeric->Memory) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* extend the tail portion of memory downwards */
+ /* ---------------------------------------------------------------------- */
+
+ Numeric->Memory = mnew ;
+
+ newmem = newsize - Numeric->size ;
+ ASSERT (newmem == 0 || newmem >= 2) ;
+
+ if (newmem >= 2)
+ {
+ /* reallocation succeeded */
+
+ /* point to the old tail marker block of size 1 + header */
+ p = Numeric->Memory + Numeric->size - 2 ;
+
+ /* create a new block out of the newly extended memory */
+ p->header.size = newmem - 1 ;
+ i = Numeric->size - 1 ;
+ p += newmem ;
+
+ /* create a new tail marker block */
+ p->header.prevsize = newmem - 1 ;
+ p->header.size = 1 ;
+
+ Numeric->size = newsize ;
+
+ /* free the new block */
+ UMF_mem_free_tail_block (Numeric, i) ;
+
+ Numeric->nrealloc++ ;
+
+ if (costly)
+ {
+ Numeric->ncostly++ ;
+ }
+
+ }
+ DEBUG1 (("Done with realloc memory\n")) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* garbage collection on the tail of Numeric->memory (destroys tuples) */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_garbage_collection (Numeric, Work) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* rebuild the tuples */
+ /* ---------------------------------------------------------------------- */
+
+ return (UMF_build_tuples (Numeric, Work)) ;
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_init_front.c b/src/sparse-matrix/umfpack/umf_init_front.c
new file mode 100644
index 0000000..15a33cb
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_init_front.c
@@ -0,0 +1,201 @@
+/* ========================================================================== */
+/* === UMF_init_front ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_init_front
+(
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, fsize, pivrow, pivcol, j, fnrows_max, fncols_max,
+ row, col, *Frows, *Fcols, *Fcpos, *Frpos, fncols, fnrows, src, dest,
+ *Wrow ;
+ Entry *Fx, *F ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ /* current front is defined by pivot row and column */
+
+ pivrow = Work->pivrow ;
+ pivcol = Work->pivcol ;
+
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+ Frpos = Work->Frpos ;
+ Fcpos = Work->Fcpos ;
+
+ Work->fnpiv = 1 ;
+ Work->fnzeros = 0 ;
+
+ /* dynamic front dimensions, but fixed across one chain */
+ fnrows_max = Work->fnrows_max ;
+ fncols_max = Work->fncols_max ;
+
+ fsize = fnrows_max * fncols_max ;
+
+ /* ---------------------------------------------------------------------- */
+ /* place pivot column pattern in frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ if (Work->pivcol_in_front)
+ {
+ /* append the pivot column extension */
+ /* note that all we need to do is increment the size, since the */
+ /* candidate pivot column pattern is already in place in */
+ /* Frows [0 ... Work->fnrows-1] (the old pattern), and */
+ /* Frows [Work->fnrows ... Work->fnrows + Work->ccdeg - 1] (the new */
+ /* pattern). */
+
+ /* if both pivrow and pivcol are in front, then we extend the old one */
+ /* in UMF_extend_front, rather than starting a new one here. */
+ ASSERT (!Work->pivrow_in_front) ;
+
+ dest = Work->fnrows ;
+ Work->fscan_row = dest ; /* only scan the new rows */
+ dest += Work->ccdeg ;
+ }
+ else
+ {
+ /* this is a completely new column */
+ dest = 0 ;
+ Work->fscan_row = 0 ; /* scan all the rows */
+
+ ASSERT (Work->Wcol == Work->Wm) ;
+ for (i = 0 ; i < Work->ccdeg ; i++)
+ {
+ row = Work->Wcol [i] ;
+ Frows [dest] = row ;
+ Frpos [row] = dest ;
+ dest++ ;
+ }
+ }
+
+ Work->fnrows = dest ;
+
+ /* place pivot row index into position */
+ Frpos [pivrow] = fnrows_max - 1 ;
+
+#ifndef NDEBUG
+ DEBUG3 (("New Pivot col "ID" now in front, length "ID"\n",
+ pivcol, Work->fnrows)) ;
+ for (i = 0 ; i < Work->fnrows ; i++)
+ {
+ DEBUG4 (("row "ID" position "ID"\n", Frows [i], Frpos [Frows [i]])) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* place pivot row pattern in frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ if (Work->pivrow_in_front)
+ {
+ /* append the pivot row extension */
+ src = Work->fncols ;
+ dest = Work->fncols ;
+ Work->fscan_col = dest ; /* only scan the new columns */
+ }
+ else
+ {
+ /* this is a completely new row */
+ src = 0 ;
+ dest = 0 ;
+ Work->fscan_col = 0 ; /* scan all the columns */
+ }
+
+ Wrow = Work->Wrow ;
+ for ( ; src < Work->rrdeg ; src++)
+ {
+ col = Wrow [src] ;
+ if (col != pivcol)
+ {
+ Fcols [dest] = col ;
+ Fcpos [col] = dest * fnrows_max ;
+ dest++ ;
+ }
+ }
+
+ Work->fncols = dest ;
+
+ /* place pivot column index into position */
+ Fcpos [pivcol] = (fncols_max - 1) * fnrows_max ;
+
+#ifndef NDEBUG
+ DEBUG3 (("New Pivot row "ID" now in front, length "ID" fnrows_max "ID"\n",
+ pivrow, Work->fncols, fnrows_max)) ;
+ for (j = 0 ; j < Work->fncols ; j++)
+ {
+ DEBUG4 (("col "ID" position "ID" ("ID")\n",
+ Fcols [j], Fcpos [Fcols [j]], j*fnrows_max)) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnrows_max) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* clear the frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ fncols = Work->fncols ;
+ fnrows = Work->fnrows ;
+ Fx = Work->Fx ;
+
+ /* clear the contribution block and the pivot row */
+ F = Fx ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ ASSERT ((&F[i] >= Fx) && (&F[i] < Fx+fsize)) ;
+ CLEAR (F [i]) ;
+ }
+ ASSERT ((&F[fnrows_max-1] >= Fx) && (&F[fnrows_max-1] < Fx+fsize)) ;
+ CLEAR (F [fnrows_max - 1]) ;
+ F += fnrows_max ;
+ }
+
+ /* clear the pivot column (excl pivot itself) */
+ F = Fx + Fcpos [pivcol] ;
+ for (j = 0 ; j < fnrows ; j++)
+ {
+ ASSERT ((&F[j] >= Fx) && (&F[j] < Fx+fsize)) ;
+ CLEAR (F [j]) ;
+ }
+
+ /* clear the pivot entry */
+ j = fsize-1 ;
+ DEBUG2 (("j "ID" fsize "ID"\n", j, fsize)) ;
+ ASSERT ((&Fx[j] >= Fx) && (&Fx[j] < Fx+fsize)) ;
+ CLEAR (Fx [j]) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* current workspace usage: */
+ /* ---------------------------------------------------------------------- */
+
+ /* Fx [0..fnrows_max-1, 0..fncols_max-1]: */
+ /* space for the new frontal matrix. */
+ /* Fx (i,j) is located at Fx [i+j*fnrows_max] */
+
+ /* ---------------------------------------------------------------------- */
+ /* make sure the pivot row and column are scanned in assembly phase */
+ /* ---------------------------------------------------------------------- */
+
+ Work->scan_pivrow = TRUE ;
+ Work->scan_pivcol = TRUE ;
+
+}
diff --git a/src/sparse-matrix/umfpack/umf_is_permutation.c b/src/sparse-matrix/umfpack/umf_is_permutation.c
new file mode 100644
index 0000000..ad54b31
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_is_permutation.c
@@ -0,0 +1,54 @@
+/* ========================================================================== */
+/* === UMF_is_permutation =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Return TRUE if P is a r-permutation vector, FALSE otherwise */
+/* P [0..r-1] must be an r-permutation of 0..n-1 */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_is_permutation
+(
+ const Int P [ ], /* permutation of size r */
+ Int W [ ], /* workspace of size n */
+ Int n,
+ Int r
+)
+{
+ Int i, k ;
+
+ if (!P)
+ {
+ /* if P is (Int *) NULL, this is the identity permutation */
+ return (TRUE) ;
+ }
+
+ ASSERT (W) ;
+
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = FALSE ;
+ }
+ for (k = 0 ; k < r ; k++)
+ {
+ i = P [k] ;
+ if (i < 0 || i >= n)
+ {
+ return (FALSE) ;
+ }
+ if (W [i])
+ {
+ return (FALSE) ;
+ }
+ W [i] = TRUE ;
+ }
+ return (TRUE) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_kernel.c b/src/sparse-matrix/umfpack/umf_kernel.c
new file mode 100644
index 0000000..318088b
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_kernel.c
@@ -0,0 +1,251 @@
+/* ========================================================================== */
+/* === UMF_kernel =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Primary factorization routine. Called by UMFPACK_numeric.
+ Returns:
+ UMFPACK_OK if successful,
+ UMFPACK_ERROR_out_of_memory if out of memory, or
+ UMFPACK_ERROR_different_pattern if pattern of matrix (Ap and/or Ai)
+ has changed since the call to UMFPACK_*symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_init_front.h"
+#include "umf_assemble.h"
+#include "umf_scale_column.h"
+#include "umf_local_search.h"
+#include "umf_create_element.h"
+#include "umf_extend_front.h"
+#include "umf_blas3_update.h"
+#include "umf_kernel_init.h"
+#include "umf_kernel_wrapup.h"
+
+
+GLOBAL Int UMF_kernel
+(
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int j, frontid1, frontid2, chain, nchains, *Chain_start, status,
+ *Chain_maxrows, *Chain_maxcols, *Front_npivcol, jmax, nb ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize memory space and load the matrix */
+ /* ---------------------------------------------------------------------- */
+
+ if (!UMF_kernel_init (Ap, Ai, Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ Numeric, Work, Symbolic))
+ {
+ /* UMF_kernel_init is guaranteed to succeed, since UMFPACK_numeric */
+ /* either allocates enough space or if not, UMF_kernel does not get */
+ /* called. So running out of memory here is a fatal error, and means */
+ /* that the user changed Ap and/or Ai since the call to */
+ /* UMFPACK_*symbolic. */
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* get the symbolic factorization */
+ /* ---------------------------------------------------------------------- */
+
+ nchains = Symbolic->nchains ;
+ Chain_start = Symbolic->Chain_start ;
+ Chain_maxrows = Symbolic->Chain_maxrows ;
+ Chain_maxcols = Symbolic->Chain_maxcols ;
+ Front_npivcol = Symbolic->Front_npivcol ;
+ DEBUG0 (("Starting Kernel, nchains "ID"\n", nchains)) ;
+ nb = Symbolic->nb ;
+ Work->nextcand = 0 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* factorize each chain of frontal matrices */
+ /* ---------------------------------------------------------------------- */
+
+ for (chain = 0 ; chain < nchains ; chain++)
+ {
+ ASSERT (Work->fnrows == 0 && Work->fncols == 0 && Work->fnpiv == 0) ;
+ frontid1 = Chain_start [chain] ;
+ frontid2 = Chain_start [chain+1] - 1 ;
+ Work->fnrows_max = Chain_maxrows [chain] ;
+ Work->fncols_max = Chain_maxcols [chain] ;
+ DEBUG2 (("Starting chain "ID". start "ID" end "ID" maxrows "ID
+ " maxcols "ID"\n", chain, frontid1, frontid2, Work->fnrows_max,
+ Work->fncols_max)) ;
+
+ /* ------------------------------------------------------------------ */
+ /* factorize each front in the chain */
+ /* ------------------------------------------------------------------ */
+
+ for (Work->frontid = frontid1 ; Work->frontid <= frontid2 ; Work->frontid++)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* there are no 0-by-c or r-by-0 fronts, where c and r are > 0 */
+ /* -------------------------------------------------------------- */
+
+ /* a front is either 0-by-0, or r-by-c */
+ DEBUG2 (("\n\n::: "ID" : Npiv: "ID" size "ID"-by-"ID"\n",
+ Work->frontid, Work->npiv,
+ Work->fnrows, Work->fncols)) ;
+ ASSERT ((Work->fnrows == 0 && Work->fncols == 0)
+ ||(Work->fnrows != 0 && Work->fncols != 0)) ;
+
+ /* -------------------------------------------------------------- */
+ /* Initialize the pivot column candidate set */
+ /* -------------------------------------------------------------- */
+
+ /* next pivot (in range 0 to n-1) */
+ Work->ncand = Front_npivcol [Work->frontid] ;
+ jmax = MIN (MAX_CANDIDATES, Work->ncand) ;
+ for (j = 0 ; j < jmax ; j++)
+ {
+ Work->Candidates [j] = Work->nextcand++ ;
+ DEBUG3 ((""ID" Candidate: "ID"\n", j, Work->Candidates [j])) ;
+ }
+
+ /* -------------------------------------------------------------- */
+ /* Assemble and factorize the current frontal matrix */
+ /* -------------------------------------------------------------- */
+
+ while (Work->ncand > 0)
+ {
+
+ /* ---------------------------------------------------------- */
+ /* get the pivot row and column */
+ /* ---------------------------------------------------------- */
+
+ status = UMF_local_search (Numeric, Work, Symbolic) ;
+ if (status == UMFPACK_ERROR_different_pattern)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ if (status == UMFPACK_WARNING_singular_matrix)
+ {
+ /* no pivot found, try again */
+ DEBUG0 (("No pivot found; try again, ncand: "ID"\n",
+ Work->ncand)) ;
+ continue ;
+ }
+
+ /* ---------------------------------------------------------- */
+ /* extend the frontal matrix, or start a new one */
+ /* ---------------------------------------------------------- */
+
+ if (Work->do_extend)
+ {
+ /* apply pending updates if front would grow too much */
+ if (Work->do_update)
+ {
+ UMF_blas3_update (Work) ;
+ }
+ /* extend the current front */
+ UMF_extend_front (Work) ;
+ }
+ else
+ {
+ /* finish the current front (if any) and start a new one */
+ if (!UMF_create_element (Numeric, Work))
+ {
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ UMF_init_front (Work) ;
+ }
+
+ /* ---------------------------------------------------------- */
+ /* Numerical & symbolic assembly into current frontal matrix */
+ /* ---------------------------------------------------------- */
+
+ UMF_assemble (Numeric, Work) ;
+
+ /* ---------------------------------------------------------- */
+ /* scale the pivot column, and save row and column of U and L */
+ /* ---------------------------------------------------------- */
+
+ if (!UMF_scale_column (Numeric, Work))
+ {
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ /* ---------------------------------------------------------- */
+ /* Numerical update if enough pivots accumulated */
+ /* ---------------------------------------------------------- */
+
+ if (Work->fnpiv >= nb)
+ {
+ UMF_blas3_update (Work) ;
+ }
+
+ Work->pivrow_in_front = FALSE ;
+ Work->pivcol_in_front = FALSE ;
+
+ /* ---------------------------------------------------------- */
+ /* If front is empty, evaporate it */
+ /* ---------------------------------------------------------- */
+
+ if (Work->fnrows == 0 || Work->fncols == 0)
+ {
+ /* This does not create an element, just evaporates. */
+ /* It ensures that a front is not 0-by-c or c-by-0. */
+ DEBUG1 (("Evaporate empty front:\n")) ;
+ (void) UMF_create_element (Numeric, Work) ;
+ Work->fnrows = 0 ;
+ Work->fncols = 0 ;
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* Wrapup the current frontal matrix. This is the last in a chain */
+ /* in the column elimination tree. The next frontal matrix */
+ /* cannot overlap with the current one, which will be its sibling */
+ /* in the column etree. */
+ /* ------------------------------------------------------------------ */
+
+ if (!UMF_create_element (Numeric, Work))
+ {
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* current front is now empty */
+ /* ------------------------------------------------------------------ */
+
+ Work->fnrows = 0 ;
+ Work->fncols = 0 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* end the last Lchain and Uchain and finalize the LU factors */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_kernel_wrapup (Numeric, Symbolic, Work) ;
+
+ /* note that the matrix may be singular */
+ return (UMFPACK_OK) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_kernel_init.c b/src/sparse-matrix/umfpack/umf_kernel_init.c
new file mode 100644
index 0000000..2eb7270
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_kernel_init.c
@@ -0,0 +1,301 @@
+/* ========================================================================== */
+/* === UMF_kernel_init ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Initialize the kernel, build tuple lists. Assumes elements are packed.
+ Returns TRUE if successful, FALSE if out of memory or if the pattern has
+ changed since UMFPACK_*symbolic. UMFPACK_numeric allocates at least enough
+ space for UMF_kernel_init to succeed; otherwise it does not call
+ UMF_kernel_init. So an out-of-memory condition means that the pattern must
+ have gotten larger.
+*/
+
+#include "umf_internal.h"
+#include "umf_tuple_lengths.h"
+#include "umf_build_tuples.h"
+#include "umf_mem_init_memoryspace.h"
+#include "umf_mem_alloc_element.h"
+
+GLOBAL Int UMF_kernel_init
+(
+ const Int Ap [ ], /* user's input matrix (not modified) */
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int row, k, oldcol, size, e, p1, p2, p, *ip, nz, *Rows, *Cols, *E, i, *Upos,
+ *Lpos, n_row, n_col, *Wp, *Cperm_init, *Frpos, *Fcpos, *Row_degree, nn,
+ *Row_tlen, *Col_degree, *Col_tlen, deg, oldrow, newrow, ilast,
+ *Rperm_init, col, n_inner ;
+ double unused = 0 ;
+ Entry *xp, *C ;
+ Element *ep ;
+
+#ifndef NDEBUG
+ double gprob_save = UMF_gprob ;
+ UMF_gprob = 0 ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG0 (("KERNEL INIT\n")) ;
+
+ n_row = Symbolic->n_row ;
+ n_col = Symbolic->n_col ;
+ nn = MAX (n_row, n_col) ;
+ n_inner = MIN (n_row, n_col) ;
+ ASSERT (n_row > 0 && n_col > 0) ;
+ Cperm_init = Symbolic->Cperm_init ;
+ Rperm_init = Symbolic->Rperm_init ;
+ nz = Ap [n_col] ;
+ if (nz < 0 || Ap [0] != 0 || nz != Symbolic->nz)
+ {
+ return (FALSE) ; /* pattern changed */
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize the Numeric->Memory space for LU, elements, and tuples */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_mem_init_memoryspace (Numeric) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize the Work and Numeric objects */
+ /* ---------------------------------------------------------------------- */
+
+ /* current front is empty */
+ Work->fnpiv = 0 ;
+ Work->fncols = 0 ;
+ Work->fnrows = 0 ;
+ Work->fnzeros = 0 ;
+
+ Work->overlap = 0 ;
+ Work->nz = nz ;
+ Work->prior_element = EMPTY ;
+ Work->ulen = 0 ;
+ Work->llen = 0 ;
+ Work->npiv = 0 ;
+ Work->frontid = 0 ;
+
+ Row_degree = Numeric->Rperm ;
+ Col_degree = Numeric->Cperm ;
+ /* Row_tuples = Numeric->Uip ; */
+ Row_tlen = Numeric->Uilen ;
+ /* Col_tuples = Numeric->Lip ; */
+ Col_tlen = Numeric->Lilen ;
+
+ Frpos = Work->Frpos ;
+ Fcpos = Work->Fcpos ;
+ Wp = Work->Wp ;
+
+ /* D = Numeric->D ; */
+ Upos = Numeric->Upos ;
+ Lpos = Numeric->Lpos ;
+ /* D [0..min(n_row,n_col)] = 0 ; no need to initialize this */
+
+ for (row = 0 ; row <= n_row ; row++)
+ {
+ Lpos [row] = EMPTY ;
+ /* Row_tuples [row] = 0 ; set in UMF_build_tuples */
+ Row_degree [row] = 0 ;
+ Row_tlen [row] = 0 ;
+ /* Frpos [row] = EMPTY ; do this later */
+ }
+
+ for (col = 0 ; col <= n_col ; col++)
+ {
+ Upos [col] = EMPTY ;
+ /* Col_tuples [col] = 0 ; set in UMF_build_tuples */
+ /* Col_degree [col] = 0 ; initialized below */
+ Col_tlen [col] = 0 ;
+ Fcpos [col] = EMPTY ;
+ }
+
+ for (i = 0 ; i <= nn ; i++)
+ {
+ Wp [i] = EMPTY ;
+ }
+ Work->Wpflag = -2 ;
+
+ /* When cleared, Wp [0..nn] is < 0 and > wpflag. */
+ /* In row search, Wp [col] is set to wpflag, which is negative. */
+ /* In col search, Wp [row] is set to a position, which is >= 0. */
+ /* Wp is cleared immediately after the row and col searches. */
+
+ /* no need to initialize Wm, Wio, Woi, and Woo */
+
+ /* clear the external degree counters */
+ Work->cdeg0 = 1 ;
+ Work->rdeg0 = 1 ;
+
+ E = Work->E ;
+
+ Numeric->n_row = n_row ;
+ Numeric->n_col = n_col ;
+ Numeric->npiv = 0 ;
+ Numeric->nnzpiv = 0 ;
+ Numeric->min_udiag = 0.0 ;
+ Numeric->max_udiag = 0.0 ;
+ Numeric->rcond = 0.0 ;
+ Numeric->isize = 0 ;
+ Numeric->nLentries = 0 ;
+ Numeric->nUentries = 0 ;
+ Numeric->lnz = 0 ;
+ Numeric->unz = 0 ;
+ Numeric->maxfrsize = 0 ;
+ Numeric->flops = 0. ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the elements, copy the columns of A, and initialize degrees */
+ /* ---------------------------------------------------------------------- */
+
+ /* also apply the row and column pre-ordering. */
+
+ DEBUG3 (("LOAD_MATRIX:\n")) ;
+
+ /* construct the inverse row permutation (use Frpos as temp) */
+ for (newrow = 0 ; newrow < n_row ; newrow++)
+ {
+ oldrow = Rperm_init [newrow] ;
+ ASSERT (oldrow >= 0 && oldrow < n_row) ;
+ Frpos [oldrow] = newrow ;
+ }
+
+ e = 0 ;
+ E [e] = 0 ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ oldcol = Cperm_init [k] ;
+ ASSERT (oldcol >= 0 && oldcol < n_col) ;
+ p1 = Ap [oldcol] ;
+ p2 = Ap [oldcol+1] ;
+ deg = p2 - p1 ;
+ Col_degree [k] = deg ;
+ if (deg < 0)
+ {
+ return (FALSE) ; /* pattern changed */
+ }
+ else if (deg > 0)
+ {
+ e++ ;
+ E [e] = UMF_mem_alloc_element (Numeric, deg, 1, &Rows, &Cols, &C,
+ &size, &ep) ;
+ if (E [e] <= 0)
+ {
+ /* We ran out of memory, which can only mean that */
+ /* the pattern (Ap and or Ai) has changed (gotten larger). */
+ DEBUG0 (("Pattern has gotten larger - alloc el. failed\n")) ;
+ DEBUG0 (("column k = "ID" size "ID"\n", k, size)) ;
+ return (FALSE) ; /* pattern changed */
+ }
+ Cols [0] = k ;
+ ip = Rows ;
+ xp = C ;
+ ilast = -1 ;
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ if (oldrow <= ilast || oldrow >= n_row)
+ {
+ return (FALSE) ; /* pattern changed */
+ }
+ ilast = oldrow ;
+ newrow = Frpos [oldrow] ;
+ *ip++ = newrow ;
+ ASSIGN (*xp, Ax [p], Az [p]) ;
+ xp++ ;
+ Row_degree [newrow]++ ;
+ }
+ }
+ }
+
+ Work->nel = e ;
+ Work->nelorig = e ;
+
+ Col_degree [n_col] = 0 ;
+
+ for (e++ ; e <= n_col + n_inner ; e++)
+ {
+ E [e] = 0 ;
+ }
+
+ /* Frpos no longer needed */
+ for (row = 0 ; row <= n_row ; row++)
+ {
+ Frpos [row] = EMPTY ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* build the tuple lists */
+ /* ---------------------------------------------------------------------- */
+
+ /* if the memory usage changes, then the pattern has changed */
+
+ (void) UMF_tuple_lengths (Numeric, Work, &unused) ;
+ if (!UMF_build_tuples (Numeric, Work))
+ {
+ /* We ran out of memory, which can only mean that */
+ /* the pattern (Ap and or Ai) has changed (gotten larger). */
+ DEBUG0 (("Pattern has gotten larger - build tuples failed\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+
+ Numeric->init_usage = Numeric->max_usage ;
+ if (Symbolic->num_mem_init_usage != Numeric->init_usage)
+ {
+ /* the pattern (Ap and or Ai) has changed */
+ DEBUG0 (("Pattern has changed in size\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+
+ /* NOTE: this test does not detect all changes to Ap and/or Ai since the */
+ /* last call to UMFPACK_*symbolic. The pattern can change with the memory*/
+ /* usage remaining the same. */
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the row merge sets */
+ /* ---------------------------------------------------------------------- */
+
+ for (i = 0 ; i <= Symbolic->nfr ; i++)
+ {
+ Work->Front_new1strow [i] = Symbolic->Front_1strow [i] ;
+ }
+
+#ifndef NDEBUG
+ UMF_dump_rowmerge (Numeric, Symbolic, Work) ;
+ DEBUG6 (("Column form of original matrix:\n")) ;
+ UMF_dump_col_matrix (Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ Ai, Ap, n_row, n_col, nz) ;
+ UMF_gprob = gprob_save ;
+ UMF_dump_memory (Numeric) ;
+ UMF_dump_matrix (Numeric, Work, FALSE) ;
+ DEBUG0 (("kernel init done...\n")) ;
+#endif
+
+ return (TRUE) ;
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_kernel_init_usage.c b/src/sparse-matrix/umfpack/umf_kernel_init_usage.c
new file mode 100644
index 0000000..9020415
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_kernel_init_usage.c
@@ -0,0 +1,54 @@
+/* ========================================================================== */
+/* === UMF_kernel_init_usage ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Return number of Units needed for initial elements by UMF_kernel_init */
+/* (including the tuples). */
+
+#include "umf_internal.h"
+#include "umf_build_tuples_usage.h"
+
+GLOBAL Int UMF_kernel_init_usage
+(
+ const Int Ap [ ],
+ const Int Row_degree [ ],
+ Int n_row,
+ Int n_col,
+ double *dusage /* input and output argument */
+)
+{
+ Int col, cdeg, usage ;
+
+ /* elements: */
+ usage = 0 ;
+ for (col = 0 ; col < n_col ; col++)
+ {
+ DEBUG2 (("col "ID" Ap["ID"] = "ID" Ap ["ID"] "ID"\n",
+ col, col+1, Ap [col+1], col, Ap [col])) ;
+ cdeg = Ap [col+1] - Ap [col] ;
+ ASSERT (cdeg >= 0) ;
+ if (cdeg > 0)
+ {
+ usage += GET_ELEMENT_SIZE (cdeg, 1) + 1 ;
+ *dusage += DGET_ELEMENT_SIZE (cdeg, 1) + 1 ;
+ }
+ }
+
+ DEBUG0 (("UMF_kernel_init_usage : original elements: "ID" %g\n",
+ usage, *dusage)) ;
+
+ /* tuples: */
+ usage += UMF_build_tuples_usage ((Int *) NULL, (Int *) NULL,
+ Row_degree, Row_degree, n_row, n_col, dusage) ;
+
+ DEBUG0 (("UMF_kernel_init_usage : all: "ID" %g\n", usage, *dusage)) ;
+ return (usage) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_kernel_wrapup.c b/src/sparse-matrix/umfpack/umf_kernel_wrapup.c
new file mode 100644
index 0000000..f686271
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_kernel_wrapup.c
@@ -0,0 +1,356 @@
+/* ========================================================================== */
+/* === UMF_kernel_wrapup ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* The matrix is factorized. Finish the LU data structure. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_kernel_wrapup
+(
+ NumericType *Numeric,
+ SymbolicType *Symbolic,
+ WorkType *Work
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, k, col, row, llen, ulen, *ip, *Rperm, *Cperm, *Lilen, npiv, lp,
+ *Uilen, *Lip, *Uip, *Cperm_init, up, pivrow, pivcol, *Lpos, *Upos, *Wr,
+ *Wc, *Wp, *Frpos, *Fcpos, *Row_degree, *Col_degree, *Rperm_init,
+ n_row, n_col, n_inner ;
+ Entry *D ;
+
+#ifndef NDEBUG
+ UMF_dump_matrix (Numeric, Work, FALSE) ;
+#endif
+
+ DEBUG0 (("Kernel complete, Starting Kernel wrapup\n")) ;
+ n_row = Symbolic->n_row ;
+ n_col = Symbolic->n_col ;
+ n_inner = MIN (n_row, n_col) ;
+ Rperm = Numeric->Rperm ;
+ Cperm = Numeric->Cperm ;
+ Lilen = Numeric->Lilen ;
+ Uilen = Numeric->Uilen ;
+ Upos = Numeric->Upos ;
+ Lpos = Numeric->Lpos ;
+ Lip = Numeric->Lip ;
+ Uip = Numeric->Uip ;
+ D = Numeric->D ;
+
+ npiv = Work->npiv ;
+ Numeric->npiv = npiv ;
+ Numeric->ulen = Work->ulen ;
+
+ ASSERT (n_row == Numeric->n_row) ;
+ ASSERT (n_col == Symbolic->n_col) ;
+ DEBUG0 (("Wrap-up: npiv "ID" ulen "ID"\n", npiv, Numeric->ulen)) ;
+ ASSERT (npiv <= n_inner) ;
+
+ /* this will be nonzero only if matrix is singular or rectangular */
+ ASSERT (IMPLIES (npiv == n_col, Work->ulen == 0)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check if matrix is singular or rectangular */
+ /* ---------------------------------------------------------------------- */
+
+ Col_degree = Cperm ; /* for NON_PIVOTAL_COL macro */
+ Row_degree = Rperm ; /* for NON_PIVOTAL_ROW macro */
+
+ if (npiv < n_row)
+ {
+ /* finalize the row permutation */
+ k = npiv ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row))
+ {
+ Rperm [row] = ONES_COMPLEMENT (k) ;
+ ASSERT (!NON_PIVOTAL_ROW (row)) ;
+ Lpos [row] = EMPTY ;
+ Uip [row] = EMPTY ;
+ Uilen [row] = 0 ;
+ k++ ;
+ }
+ }
+ ASSERT (k == n_row) ;
+ }
+
+ if (npiv < n_col)
+ {
+ /* finalize the col permutation */
+ k = npiv ;
+ for (col = 0 ; col < n_col ; col++)
+ {
+ if (NON_PIVOTAL_COL (col))
+ {
+ Cperm [col] = ONES_COMPLEMENT (k) ;
+ ASSERT (!NON_PIVOTAL_COL (col)) ;
+ Upos [col] = EMPTY ;
+ Lip [col] = EMPTY ;
+ Lilen [col] = 0 ;
+ k++ ;
+ }
+ }
+ ASSERT (k == n_col) ;
+ }
+
+ if (npiv < n_inner)
+ {
+ /* finalize the diagonal of U */
+ for (k = npiv ; k < n_inner ; k++)
+ {
+ CLEAR (D [k]) ;
+ }
+ }
+
+ /* save the pattern of the last row of U */
+ if (Numeric->ulen > 0)
+ {
+ Numeric->Upattern = Work->Upattern ;
+ Work->Upattern = (Int *) NULL ;
+ }
+
+ ASSERT (Numeric->nnzpiv <= npiv) ;
+ if (Numeric->nnzpiv < n_inner)
+ {
+ /* the rest of the diagonal is zero, so min_udiag becomes 0 */
+ Numeric->min_udiag = 0.0 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* size n_row, n_col workspaces that can be used here: */
+ /* ---------------------------------------------------------------------- */
+
+ Frpos = Work->Frpos ; /* of size n_row+1 */
+ Fcpos = Work->Fcpos ; /* of size n_col+1 */
+ Wp = Work->Wp ; /* of size MAX(n_row,n_col)+1 */
+ /* Work->Upattern ; cannot be used (in Numeric) */
+ Wr = Work->Lpattern ; /* of size n_row+1 */
+ Wc = Work->E ; /* of size n_col+n_inner+1 */
+
+ /* ---------------------------------------------------------------------- */
+ /* construct Rperm from inverse permutations */
+ /* ---------------------------------------------------------------------- */
+
+ /* use Frpos for temporary copy of inverse row permutation [ */
+
+ for (pivrow = 0 ; pivrow < n_row ; pivrow++)
+ {
+ k = Rperm [pivrow] ;
+ ASSERT (k < 0) ;
+ k = ONES_COMPLEMENT (k) ;
+ ASSERT (k >= 0 && k < n_row) ;
+ Wp [k] = pivrow ;
+ Frpos [pivrow] = k ;
+ }
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Rperm [k] = Wp [k] ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct Cperm from inverse permutation */
+ /* ---------------------------------------------------------------------- */
+
+ /* use Fcpos for temporary copy of inverse column permutation [ */
+
+ for (pivcol = 0 ; pivcol < n_col ; pivcol++)
+ {
+ k = Cperm [pivcol] ;
+ ASSERT (k < 0) ;
+ k = ONES_COMPLEMENT (k) ;
+ ASSERT (k >= 0 && k < n_col) ;
+ Wp [k] = pivcol ;
+ /* save a copy of the inverse column permutation in Fcpos */
+ Fcpos [pivcol] = k ;
+ }
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Cperm [k] = Wp [k] ;
+ }
+
+#ifndef NDEBUG
+ for (k = 0 ; k < n_col ; k++)
+ {
+ col = Cperm [k] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (Fcpos [col] == k) ; /* col is the kth pivot */
+ }
+ for (k = 0 ; k < n_row ; k++)
+ {
+ row = Rperm [k] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (Frpos [row] == k) ; /* row is the kth pivot */
+ }
+#endif
+
+#ifndef NDEBUG
+ UMF_dump_lu (Numeric) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* permute Lpos, Upos, Lilen, Lip, Uilen, and Uip */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ pivrow = Rperm [k] ;
+ Wr [k] = Uilen [pivrow] ;
+ Wp [k] = Uip [pivrow] ;
+ }
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ Uilen [k] = Wr [k] ;
+ Uip [k] = Wp [k] ;
+ }
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ pivrow = Rperm [k] ;
+ Wp [k] = Lpos [pivrow] ;
+ }
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ Lpos [k] = Wp [k] ;
+ }
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ pivcol = Cperm [k] ;
+ Wc [k] = Lilen [pivcol] ;
+ Wp [k] = Lip [pivcol] ;
+ }
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ Lilen [k] = Wc [k] ;
+ Lip [k] = Wp [k] ;
+ }
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ pivcol = Cperm [k] ;
+ Wp [k] = Upos [pivcol] ;
+ }
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ Upos [k] = Wp [k] ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* terminate the last Uchain and last Lchain */
+ /* ---------------------------------------------------------------------- */
+
+ Upos [npiv] = EMPTY ;
+ Lpos [npiv] = EMPTY ;
+ Uip [npiv] = EMPTY ;
+ Lip [npiv] = EMPTY ;
+ Uilen [npiv] = 0 ;
+ Lilen [npiv] = 0 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* convert U to the new pivot order */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ up = Uip [k] ;
+ if (up < 0)
+ {
+ /* this is the start of a new Uchain (with a pattern) */
+ ulen = Uilen [k] ;
+ DEBUG4 (("K "ID" New U. ulen "ID" End_Uchain 1\n", k, ulen)) ;
+ if (ulen > 0)
+ {
+ up = -up ;
+ ip = (Int *) (Numeric->Memory + up) ;
+ for (i = 0 ; i < ulen ; i++)
+ {
+ col = *ip ;
+ DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));
+ ASSERT (col >= 0 && col < n_col) ;
+ *ip++ = Fcpos [col] ;
+ }
+ }
+ }
+ }
+
+ ulen = Numeric->ulen ;
+ if (ulen > 0)
+ {
+ /* convert last pivot row of U to the new pivot order */
+ DEBUG4 (("K "ID" (last)\n")) ;
+ for (i = 0 ; i < ulen ; i++)
+ {
+ col = Numeric->Upattern [i] ;
+ DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])) ;
+ Numeric->Upattern [i] = Fcpos [col] ;
+ }
+ }
+
+ /* Fcpos no longer needed ] */
+
+ /* ---------------------------------------------------------------------- */
+ /* convert L to the new pivot order */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ llen = Lilen [k] ;
+ DEBUG4 (("K "ID" New L. llen "ID" \n", k, llen)) ;
+ if (llen > 0)
+ {
+ lp = Lip [k] ;
+ if (lp < 0)
+ {
+ /* this starts a new Lchain */
+ lp = -lp ;
+ }
+ ip = (Int *) (Numeric->Memory + lp) ;
+ for (i = 0 ; i < llen ; i++)
+ {
+ row = *ip ;
+ DEBUG4 ((" old row "ID" new row "ID"\n", row, Frpos [row])) ;
+ ASSERT (row >= 0 && row < n_row) ;
+ *ip++ = Frpos [row] ;
+ }
+ }
+ }
+
+ /* Frpos no longer needed ] */
+
+ /* ---------------------------------------------------------------------- */
+ /* combine symbolic and numeric permutations */
+ /* ---------------------------------------------------------------------- */
+
+ Cperm_init = Symbolic->Cperm_init ;
+ Rperm_init = Symbolic->Rperm_init ;
+
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Rperm [k] = Rperm_init [Rperm [k]] ;
+ }
+
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Cperm [k] = Cperm_init [Cperm [k]] ;
+ }
+
+ /* Work object will be freed immediately upon return (to UMF_kernel */
+ /* and then to UMFPACK_numeric). */
+}
diff --git a/src/sparse-matrix/umfpack/umf_local_search.c b/src/sparse-matrix/umfpack/umf_local_search.c
new file mode 100644
index 0000000..d70ba6f
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_local_search.c
@@ -0,0 +1,1487 @@
+/* ========================================================================== */
+/* === UMF_local_search ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Perform pivot search to find pivot row and pivot column.
+
+ The pivot column is selected from the candidate set (a supercolumn from
+ colamd), and then removed from that set.
+
+ Called by kernel.
+
+ Modifies front, but keeps current Frows and Fcols unchanged (new entries
+ are appended). This can be undone if the current front must be written
+ out after the pivot is found. The numerical values of the front are
+ unchanged.
+
+ The current frontal matrix might be empty (Fx not allocated, Work->fnrows
+ and Work->fncols are both zero).
+
+ Returns UMFPACK_OK if successful, or UMFPACK_WARNING_singular_matrix, or
+ UMFPACK_ERROR_different_pattern if not.
+
+*/
+
+/* ========================================================================== */
+
+#include "umf_internal.h"
+#include "umf_row_search.h"
+#include "umf_mem_free_tail_block.h"
+
+#define IN 0
+#define OUT 1
+
+#define IN_IN 0
+#define IN_OUT 1
+#define OUT_IN 2
+#define OUT_OUT 3
+
+/* ========================================================================== */
+
+GLOBAL Int UMF_local_search
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Entry *Fx, *Fl, *Fu, *Fs, *C, *Fd ;
+ double relax, relax2, relax3 ;
+ Int pos, nrows, *Cols, *Rows, e, f, jmax, status, max_cdeg, fnzeros,
+ j, col, i, row, cdeg [2], rdeg [2][2], fnpiv, nothing [2], new_LUsize,
+ pivrow [2][2], pivcol [2], *Wp, *Fcpos, *Frpos, new_fnzeros,
+ *Wm, *Wio, *Woi, *Woo, *Frows, *Fcols, fnrows, fncols, *E,
+ deg, nr_in, nc, src, dest, thiscost, bestcost, nr_out, *Wcol, do_update,
+ extra_cols, extra_rows, extra_zeros, relaxed_front, do_extend,
+ fnrows_max, fncols_max, tpi, *Col_tuples, *Col_degree, *Col_tlen,
+ jj, jcand [2], freebie [2], did_rowmerge ;
+ Unit *Memory, *p ;
+ Tuple *tp, *tpend, *tp1, *tp2 ;
+ Element *ep ;
+
+#ifndef NDEBUG
+ Int debug_ok, n_row, n_col, *Row_degree ;
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro only */
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ Memory = Numeric->Memory ;
+ E = Work->E ;
+ Col_degree = Numeric->Cperm ;
+
+ Col_tuples = Numeric->Lip ;
+ Col_tlen = Numeric->Lilen ;
+
+ Wp = Work->Wp ;
+ Wm = Work->Wm ;
+ Woi = Work->Woi ;
+ Wio = Work->Wio ;
+ Woo = Work->Woo ; /* size at least fncols_max */
+ Fx = Work->Fx ;
+ Fcpos = Work->Fcpos ;
+ Frpos = Work->Frpos ;
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ fnrows_max = Work->fnrows_max ;
+ fncols_max = Work->fncols_max ;
+ fnpiv = Work->fnpiv ;
+ nothing [0] = EMPTY ;
+ nothing [1] = EMPTY ;
+ relax = Numeric->relax ;
+ relax2 = Numeric->relax2 ;
+ relax3 = Numeric->relax3 ;
+ fnzeros = Work->fnzeros ;
+ new_fnzeros = fnzeros ;
+ jj = EMPTY ;
+
+ /* The pivot column degree cannot exceed max_cdeg */
+ max_cdeg = fnrows_max - fnpiv ;
+
+#ifndef NDEBUG
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ DEBUG2 (("LOCAL SEARCH: current frontal matrix: # candidates: "ID"\n",
+ Work->ncand)) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+ if (UMF_debug > 0 || MAX (n_row, n_col) < 1000)
+ {
+ for (i = 0 ; i < MAX (n_row, n_col) ; i++)
+ {
+ ASSERT (Wp [i] < 0) ;
+ ASSERT (Wp [i] > Work->Wpflag) ;
+ }
+ }
+ ASSERT (Work->Wpflag < EMPTY) ;
+ DEBUG2 (("candidates: ")) ;
+ for (j = 0 ; j < Work->ncand ; j++) DEBUG2 ((ID" ", Work->Candidates [j]));
+ DEBUG2 (("\n")) ;
+#endif
+
+ /* ====================================================================== */
+ /* === PIVOT SEARCH ===================================================== */
+ /* ====================================================================== */
+
+ /* initialize */
+
+ pivcol [IN] = EMPTY ;
+ pivcol [OUT] = EMPTY ;
+
+ /* Int_MAX is defined in umfpack.h */
+ cdeg [IN] = Int_MAX ;
+ cdeg [OUT] = Int_MAX ;
+
+ pivrow [IN][IN] = EMPTY ;
+ pivrow [IN][OUT] = EMPTY ;
+ pivrow [OUT][IN] = EMPTY ;
+ pivrow [OUT][OUT] = EMPTY ;
+
+ rdeg [IN][IN] = Int_MAX ;
+ rdeg [IN][OUT] = Int_MAX ;
+ rdeg [OUT][IN] = Int_MAX ;
+ rdeg [OUT][OUT] = Int_MAX ;
+
+ freebie [IN] = FALSE ;
+ freebie [OUT] = FALSE ;
+
+ Work->pivot_case = EMPTY ;
+ bestcost = EMPTY ;
+
+ nr_out = EMPTY ;
+ nr_in = EMPTY ;
+
+ jcand [IN] = EMPTY ;
+ jcand [OUT] = EMPTY ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find shortest column in the front, and shortest column not in the */
+ /* front, from the candidate pivot column set */
+ /* ---------------------------------------------------------------------- */
+
+ /* If there are too many candidates, then only look at the first */
+ /* MAX_CANDIDATES of them. Otherwise, if there are O(n) candidates, */
+ /* this code could take O(n^2) time. */
+
+ jmax = MIN (MAX_CANDIDATES, Work->ncand) ;
+
+#ifndef NDEBUG
+ DEBUG2 (("Max candidates "ID", Work->ncand "ID" jmax "ID"\n",
+ MAX_CANDIDATES, Work->ncand, jmax)) ;
+#endif
+
+ /* get the first candidate */
+
+ col = Work->Candidates [0] ;
+ DEBUG3 (("Pivot column candidate: "ID" j = "ID"\n", col, j)) ;
+ ASSERT (col >= 0 && col < n_col) ;
+ deg = Col_degree [col] ;
+
+#ifndef NDEBUG
+ DEBUG3 (("Pivot column candidate: "ID" cost: "ID" Fcpos[col] "ID"\n",
+ col, deg, Fcpos [col])) ;
+ UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ;
+#endif
+
+ if (Fcpos [col] >= 0)
+ {
+ /* best column in front, so far */
+ pivcol [IN] = col ;
+ cdeg [IN] = deg ;
+ jcand [IN] = 0 ;
+ }
+ else
+ {
+ /* best column not in front, so far */
+ pivcol [OUT] = col ;
+ cdeg [OUT] = deg ;
+ jcand [OUT] = 0 ;
+ }
+
+ /* look at the rest of the candidates */
+
+ for (j = 1 ; j < jmax ; j++)
+ {
+ col = Work->Candidates [j] ;
+ DEBUG3 (("Pivot column candidate: "ID" j = "ID"\n", col, j)) ;
+ ASSERT (col >= 0 && col < n_col) ;
+ deg = Col_degree [col] ;
+#ifndef NDEBUG
+ DEBUG3 (("Pivot column candidate: "ID" cost: "ID" Fcpos[col] "ID"\n",
+ col, deg, Fcpos [col])) ;
+ UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ;
+#endif
+ if (Fcpos [col] >= 0)
+ {
+#ifndef NDEBUG
+ Int fs ;
+ fs = Fcpos [col] / fnrows_max ;
+ ASSERT (fs >= 0 && fs < fncols) ;
+#endif
+ if (deg < cdeg [IN] || (deg == cdeg [IN] && col < pivcol [IN]))
+ {
+ /* best column in front, so far */
+ pivcol [IN] = col ;
+ cdeg [IN] = deg ;
+ jcand [IN] = j ;
+ }
+ }
+ else
+ {
+ if (deg < cdeg [OUT] || (deg == cdeg [OUT] && col < pivcol [OUT]))
+ {
+ /* best column not in front, so far */
+ pivcol [OUT] = col ;
+ cdeg [OUT] = deg ;
+ jcand [OUT] = j ;
+ }
+ }
+ }
+
+ DEBUG2 (("Pivcol in "ID" out "ID"\n", pivcol [IN], pivcol [OUT])) ;
+ ASSERT ((pivcol [IN] >= 0 && pivcol [IN] < n_col)
+ || (pivcol [OUT] >= 0 && pivcol [OUT] < n_col)) ;
+
+ cdeg [IN] = EMPTY ;
+ cdeg [OUT] = EMPTY ;
+
+ /* ---------------------------------------------------------------------- */
+ /* construct candidate column in front, and search for pivot rows */
+ /* ---------------------------------------------------------------------- */
+
+ if (pivcol [IN] != EMPTY)
+ {
+
+#ifndef NDEBUG
+ DEBUG2 (("col[IN] column "ID" in front at position = "ID"\n",
+ pivcol [IN], Fcpos [pivcol [IN]])) ;
+ UMF_dump_rowcol (1, Numeric, Work, pivcol [IN], TRUE) ;
+#endif
+
+ /* the only way we can have a pivcol[IN] is if the front is not empty */
+ ASSERT (fnrows > 0 && fncols > 0) ;
+
+ Fs = Fx + Fcpos [pivcol [IN]] ;
+
+ /* ------------------------------------------------------------------ */
+ /* update column in front (permanent) */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG6 (("Update pivot column:\n")) ;
+ Fl = Fx + (fncols_max - fnpiv) * fnrows_max ;
+ Fu = Fs + (fnrows_max - fnpiv) ;
+
+#ifdef USE_NO_BLAS
+
+ /* no BLAS available - use plain C code instead */
+ for (j = 0 ; j < fnpiv ; j++)
+ {
+ Entry Fuj ;
+ Fuj = Fu [j] ;
+ if (IS_NONZERO (Fuj))
+ {
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ /* Fs [i] -= Fuj * Fl [i+j*fnrows_max] ; */
+ MULT_SUB (Fs [i], Fuj, Fl [i+j*fnrows_max]) ;
+ }
+ }
+ }
+
+#else
+
+ BLAS_GEMV_COL (fnrows, fnpiv, Fl, Fu, Fs, fnrows_max) ;
+
+#endif /* USE_NO_BLAS */
+
+ /* zero out the column of U, in case this doesn't become pivot column */
+ for (j = 0 ; j < fnpiv ; j++)
+ {
+ CLEAR (Fu [j]) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+ DEBUG6 (("Fs after update: fnrows="ID"\n", fnrows)) ;
+ DEBUG6 ((" Work->fnpiv="ID" \n", fnpiv)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG6 ((ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+ EDEBUG6 (Fs [i]) ;
+ DEBUG6 (("\n")) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* construct the candidate column in the front */
+ /* ------------------------------------------------------------------ */
+
+ cdeg [IN] = fnrows ;
+
+#ifndef NDEBUG
+ /* check Frpos */
+ DEBUG5 (("COL ASSEMBLE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n",
+ cdeg [IN], pivcol [IN], max_cdeg)) ;
+ for (i = 0 ; i < cdeg [IN] ; i++)
+ {
+ row = Frows [i] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (Frpos [row] == i) ;
+ }
+ if (UMF_debug > 0 || n_row < 1000)
+ {
+ Int cnt = cdeg [IN] ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (Frpos [row] == EMPTY) cnt++ ;
+ }
+ ASSERT (cnt == n_row) ;
+ }
+#endif
+
+ ASSERT (pivcol [IN] >= 0 && pivcol [IN] < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (pivcol [IN])) ;
+
+ tpi = Col_tuples [pivcol [IN]] ;
+ if (tpi)
+ {
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Col_tlen [pivcol [IN]] ;
+ 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 ; /* column already assembled */
+ ASSERT (pivcol [IN] == Cols [f]) ;
+
+ Rows = Cols + ep->ncols ;
+ nrows = ep->nrows ;
+ p += UNITS (Int, ep->ncols + nrows) ;
+ C = ((Entry *) p) + f * nrows ;
+
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0) /* skip this if already gone from element */
+ {
+ ASSERT (row < n_row) ;
+ pos = Frpos [row] ;
+ if (pos < 0)
+ {
+ if (cdeg [IN] >= max_cdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ /* new entry in the pattern - save Frpos */
+ Frpos [row] = cdeg [IN] ;
+ Frows [cdeg [IN]] = row ;
+
+ /* this will be discarded */
+ Fs [cdeg [IN]++] = C [i] ;
+ }
+ else
+ {
+ /* entry already in pattern - sum the values */
+ /* Fs [pos] += C [i] ; */
+ ASSEMBLE (Fs [pos], C [i]) ;
+ if (pos < fnrows)
+ {
+ /* just did a permanent assembly of a single */
+ /* entry into the current front */
+ CLEAR (C [i]) ;
+ }
+ }
+ }
+ }
+
+ *tp2++ = *tp ; /* leave the tuple in the list */
+
+ }
+ Col_tlen [pivcol [IN]] = tp2 - tp1 ;
+ }
+
+ /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+ DEBUG4 (("Reduced column: cdeg in "ID"\n", cdeg [IN])) ;
+ for (i = 0 ; i < cdeg [IN] ; i++)
+ {
+ DEBUG6 ((" "ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+ EDEBUG6 (Fs [i]) ;
+ DEBUG6 (("\n")) ;
+ ASSERT (i == Frpos [Frows [i]]) ;
+ }
+ ASSERT (cdeg [IN] + fnpiv <= fnrows_max) ;
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* cdeg [IN] is now the exact degree of this column */
+ /* ------------------------------------------------------------------ */
+
+ nr_in = cdeg [IN] - fnrows ;
+
+ /* since there are no 0-by-x fronts, if there is a pivcol [IN] the */
+ /* front must have at least one row. */
+ ASSERT (cdeg [IN] > 0) ;
+
+ /* new degree of pivcol [IN], excluding current front is nr_in */
+ /* column expands by nr_in rows */
+
+ /* ------------------------------------------------------------------ */
+ /* search for two candidate pivot rows */
+ /* ------------------------------------------------------------------ */
+
+ /* for the IN_IN pivot row (if any), */
+ /* extend the pattern in place, using Fcols */
+ status = UMF_row_search (Numeric, Work, Symbolic, cdeg [IN], Frows,
+ pivrow [IN], rdeg [IN], Fcols, Wio, nothing, Fs, pivcol [IN],
+ freebie) ;
+ ASSERT (!freebie [IN] && !freebie [OUT]) ;
+
+ /* ------------------------------------------------------------------ */
+ /* fatal error if matrix pattern has changed since symbolic analysis */
+ /* ------------------------------------------------------------------ */
+
+ if (status == UMFPACK_ERROR_different_pattern)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* we now must have a structural pivot */
+ /* ------------------------------------------------------------------ */
+
+ /* Since the pivcol[IN] exists, there must be at least one row in the */
+ /* current frontal matrix, and so we must have found a structural */
+ /* pivot. The numerical value might be zero, of course. */
+
+ ASSERT (status != UMFPACK_WARNING_singular_matrix) ;
+
+ /* ------------------------------------------------------------------ */
+ /* evaluate IN_IN option */
+ /* ------------------------------------------------------------------ */
+
+ if (pivrow [IN][IN] != EMPTY)
+ {
+ /* the current front would become an (implicit) LUson */
+ /* cost is how much the current front would expand */
+
+ /* pivrow[IN][IN] candidates are not found via row merge search */
+
+ ASSERT (cdeg [IN] > 0) ;
+ nc = rdeg [IN][IN] - fncols ;
+
+ thiscost =
+ /* each column in front (except pivot column) grows by nr_in: */
+ (nr_in * (fncols - 1)) +
+ /* new columns not in old front: */
+ (nc * (cdeg [IN] - 1)) ;
+
+ /* no extra cost to relaxed amalgamation */
+
+ ASSERT (fnrows + nr_in == cdeg [IN]) ;
+ ASSERT (fncols + nc == rdeg [IN][IN]) ;
+
+ /* relaxed_front = ((fncols-1) + nc) * ((fnrows-1) + nr_in) ; */
+ do_extend = TRUE ;
+
+ DEBUG2 (("Evaluating option IN-IN:\n")) ;
+ DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",
+ Work->fnzeros, fnpiv, nr_in, nc)) ;
+ DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+ /* determine if BLAS-3 update should be applied before extending. */
+ /* update if too many zero entries accumulate in the LU block */
+ fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;
+
+ DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+ new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;
+
+ DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+ DEBUG2 (("relax2 %g\n", relax2)) ;
+
+ /* relax2 parameter uses a double relop, but ignore NaN case: */
+ do_update = (((double) fnzeros) / ((double) new_LUsize)) > relax2 ;
+
+ DEBUG2 (("do_update "ID"\n", do_update))
+
+ DEBUG2 (("option IN IN : nr "ID" nc "ID" cost "ID"(0) relax "ID
+ "\n", nr_in, nc, thiscost, do_extend)) ;
+
+ /* this is the best option seen so far */
+ Work->pivot_case = IN_IN ;
+ bestcost = thiscost ;
+
+ /* do the amalgamation and extend the front */
+ Work->do_extend = do_extend ;
+ Work->do_update = do_update ;
+ new_fnzeros = fnzeros ;
+
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* evaluate IN_OUT option */
+ /* ------------------------------------------------------------------ */
+
+ if (pivrow [IN][OUT] != EMPTY)
+ {
+ /* the current front would become a Uson of the new front */
+
+ ASSERT (cdeg [IN] > 0) ;
+
+ /* must be at least one row outside the front */
+ /* (the pivrow [IN][OUT] itself) */
+ ASSERT (nr_in >= 1) ;
+
+ /* count columns not in current front */
+ nc = 0 ;
+#ifndef NDEBUG
+ debug_ok = FALSE ;
+#endif
+ for (i = 0 ; i < rdeg [IN][OUT] ; i++)
+ {
+ col = Wio [i] ;
+ DEBUG6 (("counting col "ID" Fcpos[] = "ID"\n", col,
+ Fcpos [col])) ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ if (Fcpos [col] < 0) nc++ ;
+#ifndef NDEBUG
+ /* we must see the pivot column somewhere */
+ if (col == pivcol [IN])
+ {
+ ASSERT (Fcpos [col] >= 0) ;
+ debug_ok = TRUE ;
+ }
+#endif
+ }
+ ASSERT (debug_ok) ;
+
+ thiscost =
+ /* each row in front grows by nc: */
+ (nc * fnrows) +
+ /* new rows not affected by front: */
+ ((nr_in-1) * (rdeg [IN][OUT]-1)) ;
+
+ /* check the cost of relaxed IN_OUT amalgamation */
+
+ extra_cols = ((fncols-1) + nc ) - (rdeg [IN][OUT] - 1) ;
+ ASSERT (extra_cols >= 0) ;
+ ASSERT (fncols + nc == extra_cols + rdeg [IN][OUT]) ;
+ extra_zeros = (nr_in-1) * extra_cols ; /* symbolic fill-in */
+
+ ASSERT (fnrows + nr_in == cdeg [IN]) ;
+ ASSERT (fncols + nc == rdeg [IN][OUT] + extra_cols) ;
+
+ /* size of relaxed front: */
+ relaxed_front = ((fncols-1) + nc) * (fnrows + (nr_in-1)) ;
+
+ /* do relaxed amalgamation if the extra zeros are no more */
+ /* than a fraction (default 0.25) of the relaxed front */
+ /* if relax = 0: no extra zeros allowed */
+ /* if relax = +inf: always amalgamate */
+
+ /* relax parameter uses a double relop, but ignore NaN case: */
+ do_extend = ((double) extra_zeros)
+ < (relax * (double) relaxed_front) ;
+
+ if (do_extend)
+ {
+ /* count the cost of relaxed amalgamation */
+ thiscost += extra_zeros ;
+
+ DEBUG2 (("Evaluating option IN-OUT:\n")) ;
+ DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n",
+ Work->fnzeros, fnpiv, nr_in, nc)) ;
+ DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+ /* determine if BLAS-3 update to be applied before extending. */
+ /* update if too many zero entries accumulate in the LU block */
+ fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ;
+
+ DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+ new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ;
+
+ DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+ DEBUG2 (("relax3 %g\n", relax3)) ;
+
+ /* relax3 parameter uses a double relop, but ignore NaN case: */
+ do_update = (((double) fnzeros) / ((double) new_LUsize)) > relax3 ;
+
+ DEBUG2 (("do_update "ID"\n", do_update))
+ }
+ else
+ {
+ do_update = TRUE ;
+ fnzeros = 0 ;
+ DEBUG2 (("IN-OUT do_update forced true: "ID"\n", do_update))
+ }
+
+ DEBUG2 (("option IN OUT: nr "ID" nc "ID" cost "ID"("ID") relax "ID
+ "\n", nr_in, nc, thiscost, extra_zeros, do_extend)) ;
+
+ if (bestcost == EMPTY || thiscost < bestcost)
+ {
+ /* this is the best option seen so far */
+ Work->pivot_case = IN_OUT ;
+ bestcost = thiscost ;
+ Work->do_extend = do_extend ;
+ Work->do_update = do_update ;
+ new_fnzeros = fnzeros ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct candidate column not in front, and search for pivot rows */
+ /* ---------------------------------------------------------------------- */
+
+ if (bestcost != 0 && pivcol [OUT] != EMPTY)
+ {
+
+#ifndef NDEBUG
+ DEBUG2 (("out_col column "ID" NOT in front at position = "ID"\n",
+ pivcol [OUT], Fcpos [pivcol [OUT]])) ;
+ UMF_dump_rowcol (1, Numeric, Work, pivcol [OUT], TRUE) ;
+#endif
+
+ /* Find an empty column in the current frontal matrix to use */
+ /* as workspace. There must be one; otherwise, there couldn't be a */
+ /* candidate pivot column outside the current front. */
+
+ /* Fd: destination of final pivot column, currently unoccupied */
+ /* Use Fd as temporary workspace to construct the pivcol [OUT] */
+ Fd = Fx + (fncols_max - fnpiv - 1) * fnrows_max ;
+
+ ASSERT (fncols + fnpiv < fncols_max) ;
+
+ /* ------------------------------------------------------------------ */
+ /* construct the candidate column (currently not in the front) */
+ /* ------------------------------------------------------------------ */
+
+ /* Construct the column in Fd, Wm, using Wp for the positions: */
+ /* Wm [0..cdeg [OUT]-1] list of row indices in the column */
+ /* Fd [0..cdeg [OUT]-1] list of corresponding numerical values */
+ /* Wp [0..n-1] starts as all negative, and ends that way too. */
+
+ cdeg [OUT] = 0 ;
+
+#ifndef NDEBUG
+ /* check Wp */
+ DEBUG5 (("COL ASSEMBLE: cdeg 0\nREDUCE COL out "ID"\n", pivcol [OUT])) ;
+ if (UMF_debug > 0 || MAX (n_row, n_col) < 1000)
+ {
+ for (i = 0 ; i < MAX (n_row, n_col) ; i++)
+ {
+ ASSERT (Wp [i] < 0) ;
+ ASSERT (Wp [i] > Work->Wpflag) ;
+ }
+ }
+ DEBUG5 (("max_cdeg: "ID"\n", max_cdeg)) ;
+#endif
+
+ ASSERT (pivcol [OUT] >= 0 && pivcol [OUT] < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (pivcol [OUT])) ;
+
+ tpi = Col_tuples [pivcol [OUT]] ;
+ if (tpi)
+ {
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Col_tlen [pivcol [OUT]] ;
+ 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 ; /* column already assembled */
+ ASSERT (pivcol [OUT] == Cols [f]) ;
+
+ Rows = Cols + ep->ncols ;
+ nrows = ep->nrows ;
+ p += UNITS (Int, ep->ncols + nrows) ;
+ C = ((Entry *) p) + f * nrows ;
+
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0) /* skip this if already gone from element */
+ {
+ ASSERT (row < n_row) ;
+ pos = Wp [row] ;
+ if (pos < 0)
+ {
+ if (cdeg [OUT] >= max_cdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ /* new entry in the pattern - save Wp */
+ Wp [row] = cdeg [OUT] ;
+ Wm [cdeg [OUT]] = row ;
+ Fd [cdeg [OUT]++] = C [i] ;
+ }
+ else
+ {
+ /* entry already in pattern - sum the values */
+ /* Fd [pos] += C [i] ; */
+ ASSEMBLE (Fd [pos], C [i]) ;
+ }
+ }
+ }
+
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ Col_tlen [pivcol [OUT]] = tp2 - tp1 ;
+ }
+
+ /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+ DEBUG4 (("Reduced column: cdeg out "ID"\n", cdeg [OUT])) ;
+ for (i = 0 ; i < cdeg [OUT] ; i++)
+ {
+ DEBUG6 ((" "ID" "ID" "ID, i, Wm [i], Wp [Wm [i]])) ;
+ EDEBUG6 (Fd [i]) ;
+ DEBUG6 (("\n")) ;
+ ASSERT (i == Wp [Wm [i]]) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* Clear Wp */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < cdeg [OUT] ; i++)
+ {
+ Wp [Wm [i]] = EMPTY ; /* clear Wp */
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* new degree of pivcol [OUT] is cdeg [OUT] */
+ /* ------------------------------------------------------------------ */
+
+ /* search for two candidate pivot rows */
+ status = UMF_row_search (Numeric, Work, Symbolic, cdeg [OUT], Wm,
+ pivrow [OUT], rdeg [OUT], Woi, Woo, pivrow [IN], Fd, pivcol [OUT],
+ freebie) ;
+
+ /* ------------------------------------------------------------------ */
+ /* fatal error if matrix pattern has changed since symbolic analysis */
+ /* ------------------------------------------------------------------ */
+
+ if (status == UMFPACK_ERROR_different_pattern)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* check for rectangular, singular matrix */
+ /* ------------------------------------------------------------------ */
+
+ if (status == UMFPACK_WARNING_singular_matrix)
+ {
+ /* Pivot column is empty, and row-merge set is empty too. */
+ /* The matrix is structurally singular. */
+
+ DEBUG0 (("Warning: pivcol [OUT]: "ID" discard\n", pivcol [OUT])) ;
+
+ /* remove the failed pivcol [OUT] from candidate set */
+ jj = jcand [OUT] ;
+ ASSERT (jj >= 0 && jj < jmax) ;
+ ASSERT (pivcol [OUT] == Work->Candidates [jj]) ;
+ if (Work->ncand > MAX_CANDIDATES)
+ {
+ Work->Candidates [jj] = Work->nextcand++ ;
+ }
+ else
+ {
+ col = Work->Candidates [Work->ncand - 1] ;
+ Work->Candidates [jj] = col ;
+ Work->Candidates [Work->ncand - 1] = 0 ;
+ if (col == pivcol [IN])
+ {
+ ASSERT (jcand [IN] == Work->ncand-1) ;
+ jcand [IN] = jj ;
+ }
+ }
+ Work->ncand-- ;
+
+ /* delete all of the tuples, and all contributions to this column */
+ DEBUG1 (("Prune tuples of dead outcol: "ID"\n", pivcol [OUT])) ;
+ Col_tlen [pivcol [OUT]] = 0 ;
+ UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol [OUT]]) ;
+ Col_tuples [pivcol [OUT]] = 0 ;
+
+ if (pivcol [IN] == EMPTY)
+ {
+ /* no pivot found at all */
+ return (UMFPACK_WARNING_singular_matrix) ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+
+ /* Fd [0 .. cdeg[OUT]-1], the workspace column in the frontal matrix, */
+ /* no longer needed */
+
+ if (freebie [IN])
+ {
+ /* the "in" row is the same as the "in" row for the "in" column */
+ Woi = Fcols ;
+ rdeg [OUT][IN] = rdeg [IN][IN] ;
+ DEBUG4 (("Freebie in, row "ID"\n", pivrow [IN][IN])) ;
+ }
+
+ if (freebie [OUT])
+ {
+ /* the "out" row is the same as the "out" row for the "in" column */
+ Woo = Wio ;
+ rdeg [OUT][OUT] = rdeg [IN][OUT] ;
+ DEBUG4 (("Freebie out, row "ID"\n", pivrow [IN][OUT])) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* evaluate OUT_IN option */
+ /* ------------------------------------------------------------------ */
+
+ if (pivrow [OUT][IN] != EMPTY)
+ {
+ /* the current front would become an Lson of the new front */
+
+ did_rowmerge = (cdeg [OUT] == 0) ;
+ if (did_rowmerge)
+ {
+ /* pivrow [OUT][IN] was found via row merge search */
+ /* it is not (yet) in the pivot column pattern (add it now) */
+ if (cdeg [OUT] >= max_cdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ /* new entry in the pattern */
+ Wm [0] = pivrow [OUT][IN] ;
+ cdeg [OUT] = 1 ;
+ ASSERT (nr_out == EMPTY) ;
+ }
+
+ nc = rdeg [OUT][IN] - fncols ;
+ ASSERT (nc >= 1) ;
+
+ /* count rows not in current front */
+ nr_out = 0 ;
+#ifndef NDEBUG
+ debug_ok = FALSE ;
+#endif
+ for (i = 0 ; i < cdeg [OUT] ; i++)
+ {
+ row = Wm [i] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;
+#ifndef NDEBUG
+ /* we must see the pivot row somewhere */
+ if (row == pivrow [OUT][IN])
+ {
+ ASSERT (Frpos [row] >= 0) ;
+ debug_ok = TRUE ;
+ }
+#endif
+ }
+ ASSERT (debug_ok) ;
+
+ thiscost =
+ /* each column in front grows by nr_out: */
+ (nr_out * fncols) +
+ /* new cols not affected by front: */
+ ((nc-1) * (cdeg [OUT]-1)) ;
+
+ /* check the cost of relaxed OUT_IN amalgamation */
+
+ extra_rows = ((fnrows-1) + nr_out) - (cdeg [OUT] - 1) ;
+ ASSERT (extra_rows >= 0) ;
+ ASSERT (fnrows + nr_out == extra_rows + cdeg [OUT]) ;
+ extra_zeros = (nc-1) * extra_rows ; /* symbolic fill-in */
+
+ ASSERT (fnrows + nr_out == cdeg [OUT] + extra_rows) ;
+ ASSERT (fncols + nc == rdeg [OUT][IN]) ;
+
+ /* size of relaxed front: */
+ relaxed_front = (fncols + (nc-1)) * ((fnrows-1) + nr_out) ;
+
+ /* do relaxed amalgamation if the extra zeros are no more */
+ /* than a fraction (default 0.25) of the relaxed front */
+ /* if relax = 0: no extra zeros allowed */
+ /* if relax = +inf: always amalgamate */
+ if (did_rowmerge)
+ {
+ do_extend = FALSE ;
+ }
+ else
+ {
+ /* relax parameter uses a double relop, but ignore NaN case: */
+ do_extend = ((double) extra_zeros)
+ < (relax * (double) relaxed_front) ;
+ }
+
+ if (do_extend)
+ {
+ /* count the cost of relaxed amalgamation */
+ thiscost += extra_zeros ;
+
+ /* determine if BLAS-3 update to be applied before extending. */
+ /* update if too many zero entries accumulate in the LU block */
+
+ DEBUG2 (("Evaluating option OUT-IN:\n")) ;
+ DEBUG2 ((" Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",
+ Work->fnzeros, fnpiv, nr_out, nc)) ;
+ DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+ fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;
+
+ DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+ new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;
+
+ DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+ DEBUG2 (("relax3 %g\n", relax3)) ;
+
+ /* relax3 parameter uses a double relop, but ignore NaN case: */
+ do_update = (((double) fnzeros) / ((double) new_LUsize)) > relax3 ;
+
+ DEBUG2 (("do_update "ID"\n", do_update))
+
+ }
+ else
+ {
+ do_update = TRUE ;
+ fnzeros = 0 ;
+ DEBUG2 (("OUT-IN do_update forced true: "ID"\n", do_update))
+ }
+
+ DEBUG2 (("option OUT IN : nr "ID" nc "ID" cost "ID"("ID") relax "ID
+ "\n", nr_out, nc, thiscost, extra_zeros, do_extend)) ;
+
+ if (bestcost == EMPTY || thiscost < bestcost)
+ {
+ /* this is the best option seen so far */
+ Work->pivot_case = OUT_IN ;
+ bestcost = thiscost ;
+ Work->do_extend = do_extend ;
+ Work->do_update = do_update ;
+ new_fnzeros = fnzeros ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* evaluate OUT_OUT option */
+ /* ------------------------------------------------------------------ */
+
+ if (pivrow [OUT][OUT] != EMPTY)
+ {
+
+ did_rowmerge = (cdeg [OUT] == 0) ;
+ if (did_rowmerge)
+ {
+ /* pivrow [OUT][OUT] was found via row merge search */
+ /* it is not (yet) in the pivot column pattern (add it now) */
+ if (cdeg [OUT] >= max_cdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ /* new entry in the pattern */
+ Wm [0] = pivrow [OUT][OUT] ;
+ cdeg [OUT] = 1 ;
+ ASSERT (nr_out == EMPTY) ;
+ nr_out = 1 ;
+ }
+
+ /* count rows not in current front */
+ if (nr_out == EMPTY)
+ {
+ nr_out = 0 ;
+#ifndef NDEBUG
+ debug_ok = FALSE ;
+#endif
+ for (i = 0 ; i < cdeg [OUT] ; i++)
+ {
+ row = Wm [i] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ;
+#ifndef NDEBUG
+ /* we must see the pivot row somewhere */
+ if (row == pivrow [OUT][OUT])
+ {
+ ASSERT (Frpos [row] < 0 || Frpos [row] >= fnrows) ;
+ debug_ok = TRUE ;
+ }
+#endif
+ }
+ ASSERT (debug_ok) ;
+ }
+
+ /* count columns not in current front */
+ nc = 0 ;
+#ifndef NDEBUG
+ debug_ok = FALSE ;
+#endif
+ for (i = 0 ; i < rdeg [OUT][OUT] ; i++)
+ {
+ col = Woo [i] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ if (Fcpos [col] < 0) nc++ ;
+#ifndef NDEBUG
+ /* we must see the pivot column somewhere */
+ if (col == pivcol [OUT])
+ {
+ ASSERT (Fcpos [col] < 0) ;
+ debug_ok = TRUE ;
+ }
+#endif
+ }
+ ASSERT (debug_ok) ;
+
+ extra_cols = (fncols + (nc-1)) - (rdeg [OUT][OUT] - 1) ;
+ extra_rows = (fnrows + (nr_out-1)) - (cdeg [OUT] - 1) ;
+ ASSERT (extra_rows >= 0) ;
+ ASSERT (extra_cols >= 0) ;
+ extra_zeros = ((nc-1) * extra_rows) + ((nr_out-1) * extra_cols) ;
+
+ ASSERT (fnrows + nr_out == cdeg [OUT] + extra_rows) ;
+ ASSERT (fncols + nc == rdeg [OUT][OUT] + extra_cols) ;
+
+ thiscost =
+ /* new columns: */
+ ((nc-1) * (cdeg [OUT]-1)) +
+ /* old columns in front grow by nr_out-1: */
+ ((nr_out-1) * (fncols - extra_cols)) ;
+
+ /* size of relaxed front: */
+ relaxed_front = (fncols + (nc-1)) * (fnrows + (nr_out-1)) ;
+
+ /* do relaxed amalgamation if the extra zeros are no more */
+ /* than a fraction (default 0.25) of the relaxed front */
+ /* if relax = 0: no extra zeros allowed */
+ /* if relax = +inf: always amalgamate */
+ if (did_rowmerge)
+ {
+ do_extend = FALSE ;
+ }
+ else
+ {
+ /* relax parameter uses a double relop, but ignore NaN case: */
+ do_extend = ((double) extra_zeros)
+ < (relax * (double) relaxed_front) ;
+ }
+
+ if (do_extend)
+ {
+ /* count the cost of relaxed amalgamation */
+ thiscost += extra_zeros ;
+
+ DEBUG2 (("Evaluating option OUT-OUT:\n")) ;
+ DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n",
+ Work->fnzeros, fnpiv, nr_out, nc)) ;
+ DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ;
+
+ /* determine if BLAS-3 update to be applied before extending. */
+ /* update if too many zero entries accumulate in the LU block */
+ fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ;
+
+ DEBUG2 (("fnzeros "ID"\n", fnzeros)) ;
+
+ new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ;
+
+ DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ;
+ DEBUG2 (("relax3 %g\n", relax3)) ;
+
+ /* relax3 parameter uses a double relop, but ignore NaN case: */
+ do_update = (((double) fnzeros) / ((double) new_LUsize)) > relax3 ;
+
+ DEBUG2 (("do_update "ID"\n", do_update))
+
+ }
+ else
+ {
+ do_update = TRUE ;
+ fnzeros = 0 ;
+ DEBUG2 (("OUT-OUT do_update forced true: "ID"\n", do_update))
+ }
+
+ DEBUG2 (("option OUT OUT: nr "ID" nc "ID" cost "ID"\n",
+ rdeg [OUT][OUT], cdeg[OUT], thiscost)) ;
+
+ if (bestcost == EMPTY || thiscost < bestcost)
+ {
+ /* this is the best option seen so far */
+ Work->pivot_case = OUT_OUT ;
+ bestcost = thiscost ;
+ Work->do_extend = do_extend ;
+ Work->do_update = do_update ;
+ new_fnzeros = fnzeros ;
+ }
+ }
+ }
+
+ /* At this point, a structural pivot has been found. */
+ /* It may be numerically zero, however. */
+ ASSERT (Work->pivot_case != EMPTY) ;
+ DEBUG2 (("local seach, best option "ID", best cost "ID"\n",
+ Work->pivot_case, bestcost)) ;
+
+ /* ====================================================================== */
+ /* Pivot row and column, and extension, now determined */
+ /* ====================================================================== */
+
+ Work->fnzeros = new_fnzeros ;
+
+ /* ---------------------------------------------------------------------- */
+ /* finalize the pivot row and column */
+ /* ---------------------------------------------------------------------- */
+
+ switch (Work->pivot_case)
+ {
+ case IN_IN:
+ DEBUG2 (("IN-IN option selected\n")) ;
+ Work->pivcol_in_front = TRUE ;
+ Work->pivrow_in_front = TRUE ;
+ Work->pivcol = pivcol [IN] ;
+ Work->pivrow = pivrow [IN][IN] ;
+ Work->Wcol = (Int *) NULL ; /* not accessed */
+ Work->ccdeg = nr_in ;
+ Work->Wrow = Fcols ;
+ Work->rrdeg = rdeg [IN][IN] ;
+ jj = jcand [IN] ;
+ break ;
+
+ case IN_OUT:
+ DEBUG2 (("IN-OUT option selected\n")) ;
+ Work->pivcol_in_front = TRUE ;
+ Work->pivrow_in_front = FALSE ;
+ Work->pivcol = pivcol [IN] ;
+ Work->pivrow = pivrow [IN][OUT] ;
+ Work->Wcol = (Int *) NULL ; /* not accessed */
+ Work->ccdeg = nr_in ;
+ Work->Wrow = Wio ;
+ Work->rrdeg = rdeg [IN][OUT] ;
+ jj = jcand [IN] ;
+ break ;
+
+ case OUT_IN:
+ DEBUG2 (("OUT-IN option selected\n")) ;
+ Work->pivcol_in_front = FALSE ;
+ Work->pivrow_in_front = TRUE ;
+ Work->pivcol = pivcol [OUT] ;
+ Work->pivrow = pivrow [OUT][IN] ;
+ Work->Wcol = Wm ;
+ Work->ccdeg = cdeg [OUT] ;
+ /* Wrow might be equivalenced to Fcols (Freebie in): */
+ Work->Wrow = Woi ;
+ Work->rrdeg = rdeg [OUT][IN] ;
+ /* Work->Wrow[0..fncols-1] is not there. See Fcols instead */
+ jj = jcand [OUT] ;
+ break ;
+
+ case OUT_OUT:
+ DEBUG2 (("OUT-OUT option selected\n")) ;
+ Work->pivcol_in_front = FALSE ;
+ Work->pivrow_in_front = FALSE ;
+ Work->pivcol = pivcol [OUT] ;
+ Work->pivrow = pivrow [OUT][OUT] ;
+ Work->Wcol = Wm ;
+ Work->ccdeg = cdeg [OUT] ;
+ /* Wrow might be equivalenced to Wio (Freebie out): */
+ Work->Wrow = Woo ;
+ Work->rrdeg = rdeg [OUT][OUT] ;
+ jj = jcand [OUT] ;
+ break ;
+
+ }
+
+ Wcol = Work->Wcol ;
+
+ if (!Work->pivcol_in_front && pivcol [IN] != EMPTY)
+ {
+ /* clear Frpos if pivcol [IN] was searched, but not selected */
+ for (i = fnrows ; i < cdeg [IN] ; i++)
+ {
+ Frpos [Frows [i]] = EMPTY;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* remove pivot column from candidate pivot column list */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (jj >= 0 && jj < jmax) ;
+ ASSERT (Work->pivcol == Work->Candidates [jj]) ;
+ if (Work->ncand > MAX_CANDIDATES)
+ {
+ Work->Candidates [jj] = Work->nextcand++ ;
+ }
+ else
+ {
+ Work->Candidates [jj] = Work->Candidates [Work->ncand - 1] ;
+ Work->Candidates [Work->ncand - 1] = 0 ;
+ }
+ Work->ncand-- ;
+
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ if (!Work->pivcol_in_front)
+ {
+ DEBUG2 (("All of Wcol, size "ID"\n", Work->ccdeg)) ;
+ ASSERT (Wcol == Work->Wm) ;
+ for (i = 0 ; i < Work->ccdeg ; i++)
+ {
+ row = Wcol [i] ;
+ DEBUG2 (("Wcol row "ID" Frpos[row] "ID"\n", row, Frpos [row])) ;
+ }
+ }
+ else
+ {
+ DEBUG2 (("All of old Frows, size "ID"\n", fnrows)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG2 (("old Frows row "ID" Frpos[row] "ID"\n", row, Frpos [row]));
+ }
+ DEBUG2 (("All of (new part of Frows), size "ID"\n",Work->ccdeg));
+ for (i = fnrows ; i < fnrows + Work->ccdeg ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG2 (("new Frows row "ID" Frpos[row] "ID"\n", row, Frpos [row])) ;
+ }
+ }
+ DEBUG2 (("All of Wrow, size "ID"\n", Work->rrdeg)) ;
+ if (Work->pivrow_in_front)
+ {
+ for (i = 0 ; i < fncols ; i++)
+ {
+ col = Fcols [i] ;
+ DEBUG2 (("Wrow col "ID" Fcpos[col] "ID"\n", col, Fcpos [col])) ;
+ }
+ DEBUG2 (("---\n")) ;
+ for (i = fncols ; i < Work->rrdeg ; i++)
+ {
+ col = Work->Wrow [i] ;
+ DEBUG2 (("Wrow col "ID" Fcpos[col] "ID"\n", col, Fcpos [col])) ;
+ }
+ }
+ else
+ {
+ for (i = 0 ; i < Work->rrdeg ; i++)
+ {
+ col = Work->Wrow [i] ;
+ DEBUG2 (("Wrow col "ID" Fcpos[col] "ID"\n", col, Fcpos [col])) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* remove pivot row index from pattern of pivot column pattern, */
+ /* unless extend_front needs it. Compress the pivot column pattern. */
+ /* ---------------------------------------------------------------------- */
+
+ src = 0 ;
+ dest = 0 ;
+
+ if (Work->pivcol_in_front)
+ {
+
+ pos = Frpos [Work->pivrow] ;
+#ifndef NDEBUG
+ if ( Work->pivrow_in_front)
+ {
+ ASSERT (pos < fnrows && pos >= 0) ;
+ }
+ else
+ {
+ ASSERT (pos < cdeg [IN] && pos >= fnrows) ;
+ }
+#endif
+
+ if (!Work->pivrow_in_front)
+ {
+ ASSERT (Work->ccdeg > 0) ;
+ ASSERT (cdeg [IN] > fnrows) ;
+
+ /* remove the pivot row index by shifting the last entry into */
+ /* its position */
+ cdeg [IN]-- ;
+ Work->ccdeg-- ;
+ row = Frows [cdeg [IN]] ;
+ Frows [pos] = row ;
+ Frpos [row] = pos ;
+
+ }
+
+ }
+ else
+ {
+ if (Work->do_extend)
+ {
+ /* all cases, when front is being extended */
+ for ( ; src < Work->ccdeg ; src++)
+ {
+ ASSERT (Wcol == Work->Wm) ;
+ row = Wcol [src] ;
+ DEBUG2 (("Pruning Wcol, row "ID" (do_extend)", row)) ;
+ if (row != Work->pivrow && Frpos [row] < 0)
+ {
+ DEBUG2 ((" keep")) ;
+ Wcol [dest++] = row ;
+ }
+ DEBUG2 (("\n")) ;
+ ASSERT (IMPLIES (Work->pivcol_in_front, Frpos [row] < 0)) ;
+ }
+ /* now Wcol contains only the new rows */
+ }
+ else
+ {
+ for ( ; src < Work->ccdeg ; src++)
+ {
+ ASSERT (Wcol == Work->Wm) ;
+ row = Wcol [src] ;
+ DEBUG2 (("Pruning Wcol, row "ID" (no extend)", row)) ;
+ if (row != Work->pivrow)
+ {
+ DEBUG2 ((" keep")) ;
+ Wcol [dest++] = row ;
+ }
+ DEBUG2 (("\n")) ;
+ }
+ }
+ Work->ccdeg = dest ;
+ }
+
+
+ /* ---------------------------------------------------------------------- */
+ /* determine whether to do scan2-row and scan2-col */
+ /* ---------------------------------------------------------------------- */
+
+ if (Work->do_extend)
+ {
+ Work->do_scan2row = (fncols > 0) ;
+ Work->do_scan2col = (fnrows > 0) ;
+ }
+ else
+ {
+ Work->do_scan2row = (fncols > 0) && Work->pivrow_in_front ;
+ Work->do_scan2col = (fnrows > 0) && Work->pivcol_in_front ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG2 (("LOCAL SEARCH DONE: pivot column "ID" pivot row: "ID,
+ Work->pivcol, Work->pivrow)) ;
+ DEBUG2 ((" do_extend: "ID"\n", Work->do_extend)) ;
+ DEBUG2 (("do_update: "ID"\n", Work->do_update)) ;
+ UMF_dump_rowcol (0, Numeric, Work, Work->pivrow, TRUE) ;
+ DEBUG2 (("Pivot Wrow "ID":\n", Work->pivrow)) ;
+ if (Work->pivrow_in_front || Work->do_extend)
+ {
+ for (i = 0 ; i < fncols ; i++)
+ {
+ DEBUG3 ((" col:: "ID" \n", Fcols [i])) ;
+ }
+ }
+ for (i = ((Work->pivrow_in_front) ? fncols : 0) ; i < Work->rrdeg ; i++)
+ {
+ if (col != Work->pivcol && Fcpos [col] < 0)
+ {
+ DEBUG3 ((" col:: "ID" (new)\n", Work->Wrow [i])) ;
+ }
+ }
+ UMF_dump_rowcol (1, Numeric, Work, Work->pivcol, TRUE) ;
+ DEBUG2 (("Pivot "ID":\n", Work->pivcol)) ;
+ if (Work->pivcol_in_front || Work->do_extend)
+ {
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG3 ((" row:: "ID" \n", Frows [i])) ;
+ }
+ }
+ if (Work->pivcol_in_front)
+ {
+ for (i = fnrows ; i < fnrows + Work->ccdeg ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG3 ((" row:: "ID" (new, in Frows already)\n", Frows [i])) ;
+ ASSERT (row != Work->pivrow) ;
+ }
+ }
+ else
+ {
+ for (i = 0 ; i < Work->ccdeg ; i++)
+ {
+ ASSERT (Wcol == Work->Wm) ;
+ row = Wcol [i] ;
+ DEBUG3 ((" row:: "ID" (new)\n", row)) ;
+ ASSERT (row != Work->pivrow) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* Pivot row and column have been found */
+ /* ---------------------------------------------------------------------- */
+
+ /*
+ If pivot column index is in the front:
+ pivot column pattern (or just extension) is in
+ Work->Wcol [0..Work->ccdeg-1]
+ otherwise
+ pivot column pattern is in Frows [0.. fnrows + Work->ccdeg-1],
+ and Frpos [row] is already set properly.
+ In both cases, the pivot row index has been removed from
+ the pivot column pattern.
+
+ ------------------------------------------------------------------------
+
+ If pivot row index is in the front:
+ pivot row pattern (or just extension) is in
+ Work->Wrow [fncols..Work->rrdeg-1]
+ otherwise
+ pivot row pattern is in Work->Wrow [0..Work->rrdeg-1]
+ The pivot row pattern has not been pruned.
+
+ */
+
+ return (UMFPACK_OK) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_lsolve.c b/src/sparse-matrix/umfpack/umf_lsolve.c
new file mode 100644
index 0000000..e091b38
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_lsolve.c
@@ -0,0 +1,120 @@
+/* ========================================================================== */
+/* === UMF_lsolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* solves Lx = b, where L is the lower triangular factor of a matrix */
+/* B is overwritten with the solution X. */
+/* Returns the floating point operation count */
+
+#include "umf_internal.h"
+
+GLOBAL double UMF_lsolve
+(
+ NumericType *Numeric,
+ Entry X [ ], /* b on input, solution x on output */
+ Int Pattern [ ] /* a work array of size n */
+)
+{
+ Int k, deg, *ip, j, row, *Lpos, *Lilen, *Lip, llen, lp, newLchain,
+ pos, npiv ;
+ Entry *xp, xk ;
+
+ /* ---------------------------------------------------------------------- */
+
+ if (Numeric->n_row != Numeric->n_col) return (0.) ;
+ npiv = Numeric->npiv ;
+ Lpos = Numeric->Lpos ;
+ Lilen = Numeric->Lilen ;
+ Lip = Numeric->Lip ;
+ deg = 0 ;
+
+#ifndef NDEBUG
+ DEBUG4 (("Lsolve start:\n")) ;
+ for (j = 0 ; j < Numeric->n_row ; j++)
+ {
+ DEBUG4 (("Lsolve start "ID": ", j)) ;
+ EDEBUG4 (X [j]) ;
+ DEBUG4 (("\n")) ;
+ }
+#endif
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* make column of L in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ lp = Lip [k] ;
+ newLchain = (lp < 0) ;
+ if (newLchain)
+ {
+ lp = -lp ;
+ deg = 0 ;
+ DEBUG4 (("start of chain for column of L\n")) ;
+ }
+
+ /* remove pivot row */
+ pos = Lpos [k] ;
+ if (pos != EMPTY)
+ {
+ DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n",
+ k, Pattern [pos], pos)) ;
+ ASSERT (!newLchain) ;
+ ASSERT (deg > 0) ;
+ ASSERT (pos >= 0 && pos < deg) ;
+ ASSERT (Pattern [pos] == k) ;
+ Pattern [pos] = Pattern [--deg] ;
+ }
+
+ /* concatenate the pattern */
+ ip = (Int *) (Numeric->Memory + lp) ;
+ llen = Lilen [k] ;
+ for (j = 0 ; j < llen ; j++)
+ {
+ row = *ip++ ;
+ DEBUG4 ((" row "ID" k "ID"\n", row, k)) ;
+ ASSERT (row > k) ;
+ Pattern [deg++] = row ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* use column k of L */
+ /* ------------------------------------------------------------------ */
+
+ xk = X [k] ;
+ if (IS_NONZERO (xk))
+ {
+ xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ;
+ EDEBUG4 (*xp) ;
+ DEBUG4 (("\n")) ;
+ /* X [Pattern [j]] -= xk * (*xp) ; */
+ MULT_SUB (X [Pattern [j]], xk, *xp) ;
+ xp++ ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ for (j = 0 ; j < Numeric->n_row ; j++)
+ {
+ DEBUG4 (("Lsolve done "ID": ", j)) ;
+ EDEBUG4 (X [j]) ;
+ DEBUG4 (("\n")) ;
+ }
+ DEBUG4 (("Lsolve done.\n")) ;
+#endif
+
+ return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_ltsolve.c b/src/sparse-matrix/umfpack/umf_ltsolve.c
new file mode 100644
index 0000000..238bfba
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_ltsolve.c
@@ -0,0 +1,187 @@
+/* ========================================================================== */
+/* === UMF_ltsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Solves L'x = b or L.'x=b, where L is the lower 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_SOLVE
+UMF_lhsolve /* solve L'x=b (complex conjugate transpose) */
+#else
+UMF_ltsolve /* solve L.'x=b (array transpose) */
+#endif
+(
+ NumericType *Numeric,
+ Entry X [ ], /* b on input, solution x on output */
+ Int Pattern [ ] /* a work array of size n */
+)
+{
+ Int k, deg, *ip, j, row, *Lpos, *Lilen, kstart, kend, *Lip, llen,
+ lp, pos, npiv ;
+ Entry *xp, xk ;
+
+ /* ---------------------------------------------------------------------- */
+
+ if (Numeric->n_row != Numeric->n_col) return (0.) ;
+ npiv = Numeric->npiv ;
+ Lpos = Numeric->Lpos ;
+ Lilen = Numeric->Lilen ;
+ Lip = Numeric->Lip ;
+ kstart = npiv ;
+
+#ifndef NDEBUG
+ DEBUG4 (("Ltsolve start:\n")) ;
+ for (j = 0 ; j < Numeric->n_row ; j++)
+ {
+ DEBUG4 (("Ltsolve start "ID": ", j)) ;
+ EDEBUG4 (X [j]) ;
+ DEBUG4 (("\n")) ;
+ }
+#endif
+
+ for (kend = npiv-1 ; kend >= 0 ; kend = kstart-1)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* find the start of this Lchain */
+ /* ------------------------------------------------------------------ */
+
+ /* for (kstart = kend ; kstart >= 0 && Lip [kstart] > 0 ; kstart--) ; */
+ kstart = kend ;
+ while (kstart >= 0 && Lip [kstart] > 0)
+ {
+ kstart-- ;
+ }
+
+ /* the Lchain goes from kstart to kend */
+
+ /* ------------------------------------------------------------------ */
+ /* scan the whole chain to find the pattern of the last column of L */
+ /* ------------------------------------------------------------------ */
+
+ deg = 0 ;
+ DEBUG4 (("start of chain for column of L\n")) ;
+ for (k = kstart ; k <= kend ; k++)
+ {
+ ASSERT (k >= 0 && k < npiv) ;
+
+ /* -------------------------------------------------------------- */
+ /* make column k of L in Pattern [0..deg-1] */
+ /* -------------------------------------------------------------- */
+
+ /* remove pivot row */
+ pos = Lpos [k] ;
+ if (pos != EMPTY)
+ {
+ DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n",
+ k, Pattern [pos], pos)) ;
+ ASSERT (k != kstart) ;
+ ASSERT (deg > 0) ;
+ ASSERT (pos >= 0 && pos < deg) ;
+ ASSERT (Pattern [pos] == k) ;
+ Pattern [pos] = Pattern [--deg] ;
+ }
+
+ /* concatenate the pattern */
+ lp = Lip [k] ;
+ if (k == kstart)
+ {
+ lp = -lp ;
+ }
+ ASSERT (lp > 0) ;
+ ip = (Int *) (Numeric->Memory + lp) ;
+ llen = Lilen [k] ;
+ for (j = 0 ; j < llen ; j++)
+ {
+ row = *ip++ ;
+ DEBUG4 ((" row "ID" k "ID"\n", row, k)) ;
+ ASSERT (row > k) ;
+ Pattern [deg++] = row ;
+ }
+
+ }
+ /* Pattern [0..deg-1] is now the pattern of column kend */
+
+ /* ------------------------------------------------------------------ */
+ /* solve using this chain, in reverse order */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG4 (("Unwinding Lchain\n")) ;
+ for (k = kend ; k >= kstart ; k--)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* use column k of L */
+ /* -------------------------------------------------------------- */
+
+ ASSERT (k >= 0 && k < npiv) ;
+ lp = Lip [k] ;
+ if (k == kstart)
+ {
+ lp = -lp ;
+ }
+ ASSERT (lp > 0) ;
+ llen = Lilen [k] ;
+ xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+ xk = X [k] ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ;
+ EDEBUG4 (*xp) ;
+ DEBUG4 (("\n")) ;
+#ifdef CONJUGATE_SOLVE
+ /* xk -= X [Pattern [j]] * conjugate (*xp) ; */
+ MULT_SUB_CONJ (xk, X [Pattern [j]], *xp) ;
+#else
+ /* xk -= X [Pattern [j]] * (*xp) ; */
+ MULT_SUB (xk, X [Pattern [j]], *xp) ;
+#endif
+ xp++ ;
+ }
+ X [k] = xk ;
+
+ /* -------------------------------------------------------------- */
+ /* construct column k-1 of L */
+ /* -------------------------------------------------------------- */
+
+ /* un-concatenate the pattern */
+ deg -= llen ;
+
+ /* add pivot row */
+ pos = Lpos [k] ;
+ if (pos != EMPTY)
+ {
+ DEBUG4 ((" k "ID" adding row "ID" at position "ID"\n",
+ k, k, pos)) ;
+ ASSERT (k != kstart) ;
+ ASSERT (pos >= 0 && pos <= deg) ;
+ Pattern [deg++] = Pattern [pos] ;
+ Pattern [pos] = k ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ for (j = 0 ; j < Numeric->n_row ; j++)
+ {
+ DEBUG4 (("Ltsolve done "ID": ", j)) ;
+ EDEBUG4 (X [j]) ;
+ DEBUG4 (("\n")) ;
+ }
+ DEBUG4 (("Ltsolve done.\n")) ;
+#endif
+
+ return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_malloc.c b/src/sparse-matrix/umfpack/umf_malloc.c
new file mode 100644
index 0000000..98f5567
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_malloc.c
@@ -0,0 +1,81 @@
+/* ========================================================================== */
+/* === UMF_malloc =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Allocate a block of n objects, each of a given size. This routine does not
+ handle the case when the size is 1 (allocating char's) because of potential
+ integer overflow. UMFPACK never does that.
+ Also maintains the UMFPACK malloc count.
+*/
+
+#include "umf_internal.h"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+
+/*
+ UMF_malloc_count is a count of the objects malloc'd by UMFPACK.
+ It is increased by 7 by UMFPACK_*symbolic, and by 15 or 16 by
+ UMFPACK_*numeric. It is reduced by the same amount by the corresponding
+ UMFPACK_free_* routines. If you suspect a memory leak in your program
+ (caused by not properly destroying the Symbolic and Numeric objects)
+ then compile with -DUMF_MALLOC_COUNT and check value of UMF_malloc_count.
+ By default, UMF_MALLOC_COUNT is not defined, and thus UMFPACK has
+ no global variables.
+*/
+
+GLOBAL Int UMF_malloc_count = 0 ;
+
+#endif
+
+
+GLOBAL void *UMF_malloc
+(
+ Int n_objects,
+ size_t size_of_object
+)
+{
+ size_t size ;
+ void *p ;
+
+#ifdef UMF_TCOV_TEST
+ /* For exhaustive statement coverage testing only! */
+ /* Pretend to fail, to test out-of-memory conditions. */
+ umf_fail-- ;
+ if (umf_fail <= umf_fail_hi && umf_fail >= umf_fail_lo) { return ((void *) NULL) ; }
+#endif
+
+ /* make sure that we allocate something */
+ n_objects = MAX (1, n_objects) ;
+
+ size = (size_t) n_objects ;
+ ASSERT (size_of_object > 1) ;
+ if (size > Int_MAX / size_of_object)
+ {
+ /* object is too big for integer pointer arithmetic */
+ return ((void *) NULL) ;
+ }
+ size *= size_of_object ;
+
+ /* see umf_config.h for the memory allocator selection */
+ p = ALLOCATE (size) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+ if (p)
+ {
+ /* One more object has been malloc'ed. Keep track of the count. */
+ /* (purely for sanity checks). */
+ UMF_malloc_count++ ;
+ }
+#endif
+
+ return (p) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_mem_alloc_element.c b/src/sparse-matrix/umfpack/umf_mem_alloc_element.c
new file mode 100644
index 0000000..ac45b51
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_mem_alloc_element.c
@@ -0,0 +1,98 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_element ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* Allocate a nrows-by-ncols element, and initialize it. */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_tail_block.h"
+
+GLOBAL Int UMF_mem_alloc_element
+(
+ NumericType *Numeric,
+ Int nrows,
+ Int ncols,
+ Int **Rows,
+ Int **Cols,
+ Entry **C,
+ Int *size,
+ Element **epout
+)
+{
+
+ Element *ep ;
+ Unit *p ;
+ Int i ;
+
+ ASSERT (Numeric) ;
+ ASSERT (Numeric->Memory) ;
+
+#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 ; /* a double relop, but ignore NaN case */
+ if (UMF_allocfail)
+ {
+ DEBUG0 (("Random garbage collection (alloc_element)\n"));
+ }
+ }
+#endif
+
+ *size = GET_ELEMENT_SIZE (nrows, ncols) ;
+ if (INT_OVERFLOW (DGET_ELEMENT_SIZE (nrows, ncols) + 1))
+ {
+ DEBUG0 (("alloc element failed - problem too large\n")) ;
+ return (0) ; /* problem is too large */
+ }
+
+ i = UMF_mem_alloc_tail_block (Numeric, *size) ;
+ (*size)++ ;
+ if (!i)
+ {
+ DEBUG0 (("alloc element failed - out of memory\n")) ;
+ return (0) ; /* out of memory */
+ }
+ p = Numeric->Memory + i ;
+
+ ep = (Element *) p ;
+
+ DEBUG2 (("alloc_element done ("ID" x "ID"): p: "ID" i "ID"\n",
+ nrows, ncols, p-Numeric->Memory, i)) ;
+
+ /* Element data structure, in order: */
+ p += UNITS (Element, 1) ; /* (1) Element header */
+ *Cols = (Int *) p ; /* (2) col [0..ncols-1] indices */
+ *Rows = *Cols + ncols ; /* (3) row [0..nrows-1] indices */
+ p += UNITS (Int, ncols + nrows) ;
+ *C = (Entry *) p ; /* (4) C [0..nrows-1, 0..ncols-1] */
+
+ ep->nrows = nrows ; /* initialize the header information */
+ ep->ncols = ncols ;
+ ep->nrowsleft = nrows ;
+ ep->ncolsleft = ncols ;
+ ep->cdeg = 0 ;
+ ep->rdeg = 0 ;
+ ep->next = EMPTY ;
+
+ DEBUG2 (("new block size: "ID" ", GET_BLOCK_SIZE (Numeric->Memory + i))) ;
+ DEBUG2 (("Element size needed "ID"\n", GET_ELEMENT_SIZE (nrows, ncols))) ;
+
+ *epout = ep ;
+
+ /* return the offset into Numeric->Memory */
+ return (i) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_mem_alloc_head_block.c b/src/sparse-matrix/umfpack/umf_mem_alloc_head_block.c
new file mode 100644
index 0000000..3d62a89
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_mem_alloc_head_block.c
@@ -0,0 +1,46 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_head_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* allocate nunits from head of Numeric->Memory. No header allocated. */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_mem_alloc_head_block
+(
+ NumericType *Numeric,
+ Int nunits
+)
+{
+ Int p, usage ;
+ DEBUG2 (("GET BLOCK: from head, size "ID" ", nunits)) ;
+
+ ASSERT (Numeric) ;
+ ASSERT (Numeric->Memory) ;
+
+ if (nunits > (Numeric->itail - Numeric->ihead))
+ {
+ DEBUG2 ((" failed\n")) ;
+ return (0) ;
+ }
+
+ /* return p as an offset from Numeric->Memory */
+ p = Numeric->ihead ;
+ Numeric->ihead += nunits ;
+
+ DEBUG2 ((ID"\n", p)) ;
+ usage = Numeric->ihead + Numeric->tail_usage ;
+ Numeric->max_usage = MAX (Numeric->max_usage, usage) ;
+ return (p) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_mem_alloc_tail_block.c b/src/sparse-matrix/umfpack/umf_mem_alloc_tail_block.c
new file mode 100644
index 0000000..f8f9b39
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_mem_alloc_tail_block.c
@@ -0,0 +1,133 @@
+/* ========================================================================== */
+/* === UMF_mem_alloc_tail_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+#include "umf_internal.h"
+
+/* allocate nunits from tail of Numeric->Memory */
+/* (requires nunits+1, for header). */
+/* Returns the index into Numeric->Memory if successful, or 0 on failure. */
+
+GLOBAL Int UMF_mem_alloc_tail_block
+(
+ NumericType *Numeric,
+ Int nunits
+)
+{
+ Int bigsize, usage ;
+ Unit *p, *pnext, *pbig ;
+
+ ASSERT (Numeric) ;
+ ASSERT (Numeric->Memory) ;
+
+#ifndef NDEBUG
+ if (UMF_allocfail)
+ {
+ /* pretend to fail, to test garbage_collection */
+ UMF_allocfail = FALSE ; /* don't fail the next time */
+ return (0) ;
+ }
+ DEBUG2 (("UMF_mem_alloc_tail_block, size: "ID" + 1 = "ID": ",
+ nunits, nunits+1)) ;
+#endif
+
+ bigsize = 0 ;
+ pbig = (Unit *) NULL ;
+
+ ASSERT (nunits > 0) ; /* size must be positive */
+ if (Numeric->ibig != EMPTY)
+ {
+ ASSERT (Numeric->ibig > Numeric->itail) ;
+ ASSERT (Numeric->ibig < Numeric->size) ;
+ pbig = Numeric->Memory + Numeric->ibig ;
+ bigsize = -pbig->header.size ;
+ ASSERT (bigsize > 0) ; /* Numeric->ibig is free */
+ ASSERT (pbig->header.prevsize >= 0) ; /* prev. is not free */
+ }
+
+ if (pbig && bigsize >= nunits)
+ {
+
+ /* use the biggest block, somewhere in middle of memory */
+ p = pbig ;
+ pnext = p + 1 + bigsize ;
+ /* next is in range */
+ ASSERT (pnext < Numeric->Memory + Numeric->size) ;
+ /* prevsize of next = this size */
+ ASSERT (pnext->header.prevsize == bigsize) ;
+ /* next is not free */
+ ASSERT (pnext->header.size > 0) ;
+ bigsize -= nunits + 1 ;
+
+ if (bigsize < 4)
+ {
+ /* internal fragmentation would be too small */
+ /* allocate the entire free block */
+ p->header.size = -p->header.size ;
+ DEBUG2 (("GET BLOCK: p: "ID" size: "ID", all of big: "ID" size: "
+ ID"\n", p-Numeric->Memory, nunits, Numeric->ibig,
+ p->header.size)) ;
+ /* no more biggest block */
+ Numeric->ibig = EMPTY ;
+
+ }
+ else
+ {
+
+ /* allocate just the first nunits Units of the free block */
+ p->header.size = nunits ;
+ /* make a new free block */
+ Numeric->ibig += nunits + 1 ;
+ pbig = Numeric->Memory + Numeric->ibig ;
+ pbig->header.size = -bigsize ;
+ pbig->header.prevsize = nunits ;
+ pnext->header.prevsize = bigsize ;
+ DEBUG2 (("GET BLOCK: p: "ID" size: "ID", some of big: "ID" left: "
+ ID"\n", p-Numeric->Memory, nunits, Numeric->ibig, bigsize)) ;
+ }
+
+ }
+ else
+ {
+
+ /* allocate from the top of tail */
+ pnext = Numeric->Memory + Numeric->itail ;
+ DEBUG2 (("GET BLOCK: from tail ")) ;
+ if ((nunits + 1) > (Numeric->itail - Numeric->ihead))
+ {
+ DEBUG2 (("\n")) ;
+ return (0) ;
+ }
+ Numeric->itail -= (nunits + 1) ;
+ p = Numeric->Memory + Numeric->itail ;
+ p->header.size = nunits ;
+ p->header.prevsize = 0 ;
+ pnext->header.prevsize = nunits ;
+ DEBUG2 (("p: "ID" size: "ID", new tail "ID"\n",
+ p-Numeric->Memory, nunits, Numeric->itail)) ;
+ }
+
+ Numeric->tail_usage += p->header.size + 1 ;
+ usage = Numeric->ihead + Numeric->tail_usage ;
+ Numeric->max_usage = MAX (Numeric->max_usage, usage) ;
+
+#ifndef NDEBUG
+ UMF_debug -= 10 ;
+ UMF_dump_memory (Numeric) ;
+ UMF_debug += 10 ;
+#endif
+
+ /* p points to the header. Add one to point to the usable block itself. */
+ /* return the offset into Numeric->Memory */
+ return ((p - Numeric->Memory) + 1) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_mem_free_tail_block.c b/src/sparse-matrix/umfpack/umf_mem_free_tail_block.c
new file mode 100644
index 0000000..520277f
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_mem_free_tail_block.c
@@ -0,0 +1,149 @@
+/* ========================================================================== */
+/* === UMF_mem_free_tail_block ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+/* free a block from the tail of Numeric->memory */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_mem_free_tail_block
+(
+ NumericType *Numeric,
+ Int i
+)
+{
+ Unit *pprev, *pnext, *p, *pbig ;
+ Int sprev ;
+
+ ASSERT (Numeric) ;
+ ASSERT (Numeric->Memory) ;
+ if (i == EMPTY || i == 0) return ; /* already deallocated */
+
+ /* ---------------------------------------------------------------------- */
+ /* get the block */
+ /* ---------------------------------------------------------------------- */
+
+ p = Numeric->Memory + i ;
+
+ p-- ; /* get the corresponding header */
+ DEBUG2 (("free block: p: "ID, p-Numeric->Memory)) ;
+ ASSERT (p >= Numeric->Memory + Numeric->itail) ;
+ ASSERT (p < Numeric->Memory + Numeric->size) ;
+ ASSERT (p->header.size > 0) ; /* block not already free */
+ ASSERT (p->header.prevsize >= 0) ;
+
+ Numeric->tail_usage -= p->header.size + 1 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* merge with next free block, if any */
+ /* ---------------------------------------------------------------------- */
+
+ pnext = p + 1 + p->header.size ;
+ DEBUG2 (("size: "ID" next: "ID" ", p->header.size, pnext-Numeric->Memory)) ;
+ ASSERT (pnext < Numeric->Memory + Numeric->size) ;
+ ASSERT (pnext->header.prevsize == p->header.size) ;
+ ASSERT (pnext->header.size != 0) ;
+
+ if (pnext->header.size < 0)
+ {
+ /* next block is also free - merge with current block */
+ p->header.size += (-pnext->header.size) + 1 ;
+ DEBUG2 ((" NEXT FREE ")) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* merge with previous free block, if any */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ if (p == Numeric->Memory + Numeric->itail)
+ {
+ DEBUG2 ((" at top of tail ")) ;
+ ASSERT (p->header.prevsize == 0) ;
+ }
+#endif
+
+ if (p > Numeric->Memory + Numeric->itail)
+ {
+ ASSERT (p->header.prevsize > 0) ;
+ pprev = p - 1 - p->header.prevsize ;
+ DEBUG2 ((" prev: "ID" ", pprev-Numeric->Memory)) ;
+ ASSERT (pprev >= Numeric->Memory + Numeric->itail) ;
+ sprev = pprev->header.size ;
+ if (sprev < 0)
+ {
+ /* previous block is also free - merge it with current block */
+ ASSERT (p->header.prevsize == -sprev) ;
+ pprev->header.size = p->header.size + (-sprev) + 1 ;
+ p = pprev ;
+ DEBUG2 ((" PREV FREE ")) ;
+ /* note that p may now point to Numeric->itail */
+ }
+#ifndef NDEBUG
+ else
+ {
+ ASSERT (p->header.prevsize == sprev) ;
+ }
+#endif
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* free the block, p */
+ /* ---------------------------------------------------------------------- */
+
+ pnext = p + 1 + p->header.size ;
+ ASSERT (pnext < Numeric->Memory + Numeric->size) ;
+
+ if (p == Numeric->Memory + Numeric->itail)
+ {
+ /* top block in list is freed */
+ Numeric->itail = pnext - Numeric->Memory ;
+ pnext->header.prevsize = 0 ;
+ DEBUG2 ((" NEW TAIL : "ID" ", Numeric->itail)) ;
+ ASSERT (pnext->header.size > 0) ;
+ if (Numeric->ibig != EMPTY && Numeric->ibig <= Numeric->itail)
+ {
+ /* the big free block is now above the tail */
+ Numeric->ibig = EMPTY ;
+ }
+ }
+ else
+ {
+ /* keep track of the biggest free block seen */
+ if (Numeric->ibig == EMPTY)
+ {
+ Numeric->ibig = p - Numeric->Memory ;
+ }
+ else
+ {
+ pbig = Numeric->Memory + Numeric->ibig ;
+ if (-(pbig->header.size) < p->header.size)
+ {
+ Numeric->ibig = p - Numeric->Memory ;
+ }
+ }
+ /* flag the block as free, somewhere in the middle of the tail */
+ pnext->header.prevsize = p->header.size ;
+ p->header.size = -p->header.size ;
+ }
+
+ DEBUG2 (("new p: "ID" freesize: "ID"\n", p-Numeric->Memory,
+ -p->header.size)) ;
+
+#ifndef NDEBUG
+ UMF_debug -= 10 ;
+ UMF_dump_memory (Numeric) ;
+ UMF_debug += 10 ;
+#endif
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_mem_init_memoryspace.c b/src/sparse-matrix/umfpack/umf_mem_init_memoryspace.c
new file mode 100644
index 0000000..c4d1c5f
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_mem_init_memoryspace.c
@@ -0,0 +1,65 @@
+/* ========================================================================== */
+/* === UMF_mem_init_memoryspace ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* The UMF_mem_* routines manage the Numeric->Memory memory space. */
+
+#include "umf_internal.h"
+
+/* initialize the LU and element workspace (Numeric->Memory) */
+
+GLOBAL void UMF_mem_init_memoryspace
+(
+ NumericType *Numeric
+)
+{
+ Unit *p ;
+
+ ASSERT (Numeric) ;
+ ASSERT (Numeric->size >= 4) ;
+ DEBUG0 (("Init memory space, size "ID"\n", Numeric->size)) ;
+
+ Numeric->ngarbage = 0 ;
+ Numeric->nrealloc = 0 ;
+ Numeric->ncostly = 0 ;
+ Numeric->ibig = EMPTY ;
+ Numeric->ihead = 0 ;
+ Numeric->itail = Numeric->size ;
+
+#ifndef NDEBUG
+ UMF_allocfail = FALSE ;
+#endif
+
+ /* allocate the 2-unit tail marker block and initialize it */
+ Numeric->itail -= 2 ;
+ p = Numeric->Memory + Numeric->itail ;
+ DEBUG2 (("p "ID" tail "ID"\n", p-Numeric->Memory, Numeric->itail)) ;
+ Numeric->tail_usage = 2 ;
+ p->header.prevsize = 0 ;
+ p->header.size = 1 ;
+
+ /* allocate a 1-unit head marker block at the head of memory */
+ /* this is done so that an offset of zero is treated as a NULL pointer */
+ Numeric->ihead++ ;
+
+ /* initial usage in Numeric->Memory */
+ Numeric->max_usage = 3 ;
+ Numeric->init_usage = Numeric->max_usage ;
+
+ /* Note that UMFPACK_*symbolic ensures that Numeric->Memory is of size */
+ /* at least 3, so this initialization will always succeed. */
+
+#ifndef NDEBUG
+ DEBUG2 (("init_memoryspace, all free (except one unit at head\n")) ;
+ UMF_dump_memory (Numeric) ;
+#endif
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_order_front_tree.c b/src/sparse-matrix/umfpack/umf_order_front_tree.c
new file mode 100644
index 0000000..d322c65
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_order_front_tree.c
@@ -0,0 +1,100 @@
+/* ========================================================================== */
+/* === UMF_order_front_tree ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Post-ordering of supernodal column elimination tree.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_order_front_tree
+(
+ Int root,
+ Int k,
+ Int Front_child [ ], /* input argument, destroyed */
+ const Int Front_sibling [ ],
+ Int Front_order [ ],
+ Int Stack [ ]
+)
+{
+ Int f, head, h, i ;
+
+/* recursive version (Stack [ ] is not used):
+ i = root ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ k = UMF_order_front_tree (f, k, Front_child, Front_sibling,
+ Front_order) ;
+ }
+ Front_order [i] = k++ ;
+ return (k) ;
+*/
+
+ /* push root on the stack */
+ head = 0 ;
+ Stack [0] = root ;
+
+ while (head >= 0)
+ {
+ /* get head of stack */
+ i = Stack [head] ;
+ DEBUG1 (("head of stack "ID" \n", i)) ;
+ ASSERT (i >= 0 && i < UMF_nbug && head <= UMF_fbug) ;
+
+ if (Front_child [i] != EMPTY)
+ {
+ /* the children of i are not yet ordered */
+ /* push each child onto the stack in reverse order */
+ /* so that small ones at the head of the list get popped first */
+ /* and the biggest one at the end of the list gets popped last */
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ head++ ;
+ }
+ h = head ;
+ ASSERT (head <= UMF_fbug) ;
+ for (f = Front_child [i] ; f != EMPTY ; f = Front_sibling [f])
+ {
+ Stack [h--] = f ;
+ DEBUG1 (("push "ID" on stack\n", f)) ;
+ ASSERT (f >= 0 && f < UMF_nbug) ;
+ }
+ ASSERT (Stack [h] == i) ;
+
+ /* delete child list so that i gets ordered next time we see it */
+ Front_child [i] = EMPTY ;
+ }
+ else
+ {
+ /* the children of i (if there were any) are already ordered */
+ /* remove i from the stack and order it. Front i is kth front */
+ head-- ;
+ DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
+ Front_order [i] = k++ ;
+ ASSERT (k <= UMF_fbug) ;
+ }
+
+#ifndef NDEBUG
+ DEBUG1 (("\nStack:")) ;
+ for (h = head ; h >= 0 ; h--)
+ {
+ Int j = Stack [h] ;
+ DEBUG1 ((" "ID, j)) ;
+ ASSERT (j >= 0 && j < UMF_nbug) ;
+ }
+ DEBUG1 (("\n\n")) ;
+ ASSERT (head < UMF_fbug) ;
+#endif
+
+ }
+ return (k) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_realloc.c b/src/sparse-matrix/umfpack/umf_realloc.c
new file mode 100644
index 0000000..34ccc68
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_realloc.c
@@ -0,0 +1,56 @@
+/* ========================================================================== */
+/* === UMF_realloc ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Realloc a block previously allocated by UMF_malloc.
+ Return NULL on failure (in which case the block is still allocated, and will
+ be kept at is present size). This routine is only used for Numeric->Memory.
+*/
+
+#include "umf_internal.h"
+
+
+
+GLOBAL void *UMF_realloc
+(
+ void *p,
+ Int n_objects,
+ size_t size_of_object
+)
+{
+ size_t size ;
+
+#ifdef UMF_TCOV_TEST
+ /* For exhaustive statement coverage testing only! */
+ /* Pretend to fail, to test out-of-memory conditions. */
+ umf_realloc_fail-- ;
+ if (umf_realloc_fail <= umf_realloc_hi && umf_realloc_fail >= umf_realloc_lo) { return ((void *) NULL) ; }
+#endif
+
+ /* make sure that we allocate something */
+ n_objects = MAX (1, n_objects) ;
+
+ size = (size_t) n_objects ;
+ ASSERT (size_of_object > 1) ;
+ if (size > Int_MAX / size_of_object)
+ {
+ /* object is too big for integer pointer arithmetic */
+ return ((void *) NULL) ;
+ }
+ size *= size_of_object ;
+
+ DEBUG0 (("UMF_realloc n_objects "ID" size_of_object "ID"\n",
+ n_objects, (Int) size_of_object)) ;
+
+ /* see umf_config.h for the memory allocator selection */
+ return (REALLOCATE (p, size)) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_row_search.c b/src/sparse-matrix/umfpack/umf_row_search.c
new file mode 100644
index 0000000..1d65afc
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_row_search.c
@@ -0,0 +1,626 @@
+/* ========================================================================== */
+/* === UMF_row_search ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Find two candidate pivot rows in a column: the best one in the front,
+ and the best one not in the front. Return the two pivot row patterns and
+ their exact degrees. Called by UMF_local_search.
+
+ Returns UMFPACK_OK if successful, or UMFPACK_WARNING_singular_matrix or
+ UMFPACK_ERROR_different_pattern if not.
+
+*/
+
+#include "umf_internal.h"
+
+#define IN 0
+#define OUT 1
+
+GLOBAL Int UMF_row_search
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic,
+ Int cdeg, /* length of column */
+ const Int Pattern [ ], /* pattern of column */
+ Int pivrow [2], /* pivrow [IN] and pivrow [OUT] */
+ Int rdeg [2], /* rdeg [IN] and rdeg [OUT] */
+ Int W_i [ ], /* pattern of pivrow [IN], */
+ /* either Fcols or Woi */
+ Int W_o [ ], /* pattern of pivrow [OUT], */
+ /* either Wio or Woo */
+ Int prior_pivrow [2], /* the two other rows just scanned, if any */
+ const Entry Fcol [ ], /* numerical values in column */
+ /* (a column in the front) */
+
+ Int pivcol, /* the candidate column being searched */
+ Int freebie [ ]
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ double maxval, toler, value ;
+ Int i, row, deg, *Wp, col, *Frpos, fnrows, *E, j, ncols, *Cols, *Rows,
+ e, f, wpflag, *Fcpos, fncols, tpi, max_rdeg, nans_in_col ;
+ Tuple *tp, *tpend, *tp1, *tp2 ;
+ Unit *Memory, *p ;
+ Element *ep ;
+ Int *Row_tuples, *Row_degree, *Row_tlen ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ Row_degree = Numeric->Rperm ;
+ Row_tuples = Numeric->Uip ;
+ Row_tlen = Numeric->Uilen ;
+ Wp = Work->Wp ;
+ Frpos = Work->Frpos ;
+ E = Work->E ;
+ Memory = Numeric->Memory ;
+ fnrows = Work->fnrows ;
+
+ /* pivot row degree cannot exceed max_rdeg */
+ max_rdeg = Work->fncols_max - Work->fnpiv ;
+
+ /* ---------------------------------------------------------------------- */
+ /* scan pivot column for candidate rows */
+ /* ---------------------------------------------------------------------- */
+
+ maxval = 0.0 ;
+ nans_in_col = FALSE ;
+ for (i = 0 ; i < cdeg ; i++)
+ {
+ APPROX_ABS (value, Fcol [i]) ;
+ if (SCALAR_IS_NAN (value))
+ {
+ nans_in_col = TRUE ;
+ maxval = value ;
+ break ;
+ }
+ /* This test can now ignore the NaN case: */
+ maxval = MAX (maxval, value) ;
+ }
+
+ /* if maxval is zero, the matrix is numerically singular */
+
+ toler = Numeric->relpt * maxval ;
+ if (SCALAR_IS_ZERO (toler))
+ {
+ /* guard against underflow, and relpt=0 means relpt=1 */
+ toler = maxval ;
+ }
+ DEBUG5 (("Row_search begins [ maxval %g toler %g\n", maxval, toler)) ;
+ if (SCALAR_IS_NAN (toler))
+ {
+ nans_in_col = TRUE ;
+ }
+
+ if (!nans_in_col)
+ {
+ for (i = 0 ; i < cdeg ; i++)
+ {
+ double a ;
+ APPROX_ABS (a, Fcol [i]) ;
+
+ /* No NaN's exist in this column */
+ ASSERT (!SCALAR_IS_NAN (a)) ;
+ ASSERT (!SCALAR_IS_NAN (toler)) ;
+
+ if (a >= toler) /* a double relop, but no NaN's exist here. */
+ {
+ row = Pattern [i] ;
+ deg = Row_degree [row] ;
+#ifndef NDEBUG
+ DEBUG6 ((ID" Candidate row "ID" deg "ID" absval %g\n", i, row,
+ deg, a)) ;
+ UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+#endif
+
+ if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+ {
+ /* row is in the current front */
+ DEBUG4 ((" in front\n")) ;
+ if (deg < rdeg [IN]
+ || (deg == rdeg [IN] && row < pivrow [IN]))
+ {
+ /* best row in front, so far */
+ pivrow [IN] = row ;
+ rdeg [IN] = deg ;
+ }
+ }
+ else
+ {
+ /* row is not in the current front */
+ DEBUG4 ((" NOT in front\n")) ;
+ if (deg < rdeg [OUT]
+ || (deg == rdeg[OUT] && row < pivrow[OUT]))
+ {
+ /* best row not in front, so far */
+ pivrow [OUT] = row ;
+ rdeg [OUT] = deg ;
+ }
+ }
+ }
+ }
+ }
+
+ /* if cdeg > 0 then we must have found a pivot row ... unless NaN's */
+ /* exist. Try with no numerical tests if no pivot found. */
+
+ if (cdeg > 0 && pivrow [IN] == EMPTY && pivrow [OUT] == EMPTY)
+ {
+ /* cleanup for the NaN case */
+ DEBUG0 (("Found a NaN in pivot column!\n")) ;
+
+ /* grab the first entry in the pivot column, ignoring degree and */
+ /* numerical stability. */
+ row = Pattern [0] ;
+ deg = Row_degree [row] ;
+ if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+ {
+ /* row is in the current front */
+ DEBUG4 ((" in front\n")) ;
+ pivrow [IN] = row ;
+ rdeg [IN] = deg ;
+ }
+ else
+ {
+ /* row is not in the current front */
+ DEBUG4 ((" NOT in front\n")) ;
+ pivrow [OUT] = row ;
+ rdeg [OUT] = deg ;
+ }
+
+ /* We are now guaranteed to have a pivot, no matter how broken */
+ /* (non-IEEE compliant) the underlying numerical operators are. */
+ /* This is particularly a problem for Microsoft compilers (they do */
+ /* not handle NaN's properly). Now try to find a sparser pivot, if */
+ /* possible. */
+
+ for (i = 1 ; i < cdeg ; i++)
+ {
+ row = Pattern [i] ;
+ deg = Row_degree [row] ;
+
+ if (Frpos [row] >= 0 && Frpos [row] < fnrows)
+ {
+ /* row is in the current front */
+ DEBUG4 ((" in front\n")) ;
+ if (deg < rdeg [IN] || (deg == rdeg [IN] && row < pivrow [IN]))
+ {
+ /* best row in front, so far */
+ pivrow [IN] = row ;
+ rdeg [IN] = deg ;
+ }
+ }
+ else
+ {
+ /* row is not in the current front */
+ DEBUG4 ((" NOT in front\n")) ;
+ if (deg < rdeg [OUT] || (deg == rdeg[OUT] && row < pivrow[OUT]))
+ {
+ /* best row not in front, so far */
+ pivrow [OUT] = row ;
+ rdeg [OUT] = deg ;
+ }
+ }
+ }
+ }
+
+ /* We found a pivot if there are entries (even zero ones) in pivot col */
+ ASSERT (IMPLIES (cdeg > 0, pivrow [IN] != EMPTY || pivrow [OUT] != EMPTY)) ;
+
+ /* If there are no entries in the pivot column, then no pivot is found */
+ ASSERT (IMPLIES (cdeg== 0, pivrow [IN] == EMPTY && pivrow [OUT] == EMPTY)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check for singular matrix */
+ /* ---------------------------------------------------------------------- */
+
+ if (cdeg == 0)
+ {
+ if (fnrows > 0)
+ {
+ /*
+ Get the pivrow [OUT][IN] from the current front.
+ The frontal matrix looks like this:
+
+ pivcol[OUT]
+ |
+ v
+ x x x x 0 <- so grab this row as the pivrow [OUT][IN].
+ x x x x 0
+ x x x x 0
+ 0 0 0 0 0
+
+ The current frontal matrix has some rows in it. The degree
+ of the pivcol[OUT] is zero. The column is empty, and the
+ current front does not contribute to it.
+
+ */
+ pivrow [IN] = Work->Frows [0] ;
+ DEBUG0 (("Got zero pivrow[OUT][IN] "ID" from current front\n",
+ pivrow [IN])) ;
+ }
+ else
+ {
+
+ /*
+ Get a pivot row from the row-merge tree, use as
+ pivrow [OUT][OUT]. pivrow [IN] remains EMPTY.
+ This can only happen if the current front is 0-by-0.
+ */
+
+ Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1,
+ row2, fleftmost, nfr, n_row, frontid ;
+
+ ASSERT (Work->fncols == 0) ;
+
+ Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+ Front_1strow = Symbolic->Front_1strow ;
+ Front_new1strow = Work->Front_new1strow ;
+ nfr = Symbolic->nfr ;
+ n_row = Numeric->n_row ;
+ frontid = Work->frontid ;
+
+ DEBUG0 (("Warning: pivcol: "ID" is empty front "ID"\n",
+ pivcol, frontid)) ;
+#ifndef NDEBUG
+ DEBUG1 (("Calling dump rowmerge\n")) ;
+ UMF_dump_rowmerge (Numeric, Symbolic, Work) ;
+#endif
+
+ /* Row-merge set is the non-pivotal rows in the range */
+ /* Front_new1strow [Front_leftmostdesc [frontid]] to */
+ /* Front_1strow [frontid+1] - 1. */
+ /* If this is empty, then use the empty rows, in the range */
+ /* Front_new1strow [nfr] to n_row-1. */
+ /* If this too is empty, then pivrow [OUT] will be empty. */
+ /* In both cases, update Front_new1strow [...]. */
+
+ fleftmost = Front_leftmostdesc [frontid] ;
+ row1 = Front_new1strow [fleftmost] ;
+ row2 = Front_1strow [frontid+1] - 1 ;
+ DEBUG1 (("Leftmost: "ID" Rows ["ID" to "ID"] srch ["ID" to "ID"]\n",
+ fleftmost, Front_1strow [frontid], row2, row1, row2)) ;
+
+ /* look in the range row1 ... row2 */
+ for (row = row1 ; row <= row2 ; row++)
+ {
+ DEBUG2 ((" Row: "ID"\n", row)) ;
+ if (NON_PIVOTAL_ROW (row))
+ {
+ /* found it */
+ DEBUG2 ((" Row: "ID" found\n", row)) ;
+ ASSERT (Frpos [row] == EMPTY) ;
+ pivrow [OUT] = row ;
+ break ;
+ }
+ }
+ Front_new1strow [fleftmost] = row ;
+
+ if (pivrow [OUT] == EMPTY)
+ {
+ /* not found, look in empty row set in "dummy" front */
+ row1 = Front_new1strow [nfr] ;
+ row2 = n_row-1 ;
+ DEBUG2 (("Empty: "ID" Rows ["ID" to "ID"] srch["ID" to "ID"]\n",
+ nfr, Front_1strow [nfr], row2, row1, row2)) ;
+
+ /* look in the range row1 ... row2 */
+ for (row = row1 ; row <= row2 ; row++)
+ {
+ DEBUG2 ((" Empty Row: "ID"\n", row)) ;
+ if (NON_PIVOTAL_ROW (row))
+ {
+ /* found it */
+ DEBUG2 ((" Empty Row: "ID" found\n", row)) ;
+ ASSERT (Frpos [row] == EMPTY) ;
+ pivrow [OUT] = row ;
+ break ;
+ }
+ }
+ Front_new1strow [nfr] = row ;
+ }
+
+ if (pivrow [OUT] == EMPTY)
+ {
+ /* Row-merge set is empty. We can just discard */
+ /* the candidate pivot column. */
+ DEBUG0 (("Warning: row-merge set empty\n")) ;
+ return (UMFPACK_WARNING_singular_matrix) ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the candidate row in the front, if any */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG4 (("pivrow [IN]: "ID"\n", pivrow [IN])) ;
+ UMF_dump_rowcol (0, Numeric, Work, pivrow [IN], TRUE) ;
+#endif
+
+ if (pivrow [IN] != EMPTY)
+ {
+
+ /* the row merge candidate row is not pivrow [IN] */
+ freebie [IN] = (pivrow [IN] == prior_pivrow [IN]) && (cdeg > 0) ;
+ ASSERT (cdeg >= 0) ;
+
+ if (!freebie [IN])
+ {
+ /* include current front in the degree of this row */
+
+ Fcpos = Work->Fcpos ;
+ fncols = Work->fncols ;
+
+ wpflag = Work->Wpflag ;
+ ASSERT (wpflag < EMPTY) ;
+
+ /* -------------------------------------------------------------- */
+ /* construct the pattern of the IN row */
+ /* -------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ /* check Fcols */
+ DEBUG5 (("ROW ASSEMBLE: rdeg "ID"\nREDUCE ROW "ID"\n",
+ fncols, pivrow [IN])) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ col = Work->Fcols [j] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (Fcpos [col] >= 0) ;
+ }
+ if (UMF_debug > 0 || Work->n_col < 1000)
+ {
+ Int cnt = fncols ;
+ for (col = 0 ; col < Work->n_col ; col++)
+ {
+ if (Fcpos [col] < 0) cnt++ ;
+ }
+ ASSERT (cnt == Work->n_col) ;
+ }
+ /* check Wp */
+ if (UMF_debug > 0 || MAX (Work->n_row, Work->n_col) < 1000)
+ {
+ for (i = 0 ; i < MAX (Work->n_row, Work->n_col) ; i++)
+ {
+ ASSERT (Wp [i] < 0) ;
+ ASSERT (Wp [i] > wpflag) ;
+ }
+ }
+#endif
+
+ rdeg [IN] = fncols ;
+
+ ASSERT (pivrow [IN] >= 0 && pivrow [IN] < Work->n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (pivrow [IN])) ;
+
+ /* add the pivot column itself */
+ if (Wp [pivcol] > wpflag && Fcpos [pivcol] < 0)
+ {
+ DEBUG0 (("Adding pivot col to pivrow [IN] pattern\n")) ;
+ if (rdeg [IN] >= max_rdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wp [pivcol] = wpflag ;
+ W_i [rdeg [IN]++] = pivcol ;
+ }
+
+ tpi = Row_tuples [pivrow [IN]] ;
+ if (tpi)
+ {
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Row_tlen [pivrow [IN]] ;
+ 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 ;
+ ncols = ep->ncols ;
+ Rows = Cols + ncols ;
+ if (Rows [f] == EMPTY)
+ {
+ continue ; /* row already assembled */
+ }
+ ASSERT (pivrow [IN] == Rows [f]) ;
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if ((col >= 0) && (Wp [col] > wpflag) && Fcpos [col] <0)
+ {
+ if (rdeg [IN] >= max_rdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wp [col] = wpflag ;
+ W_i [rdeg [IN]++] = col ;
+ }
+ }
+
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ Row_tlen [pivrow [IN]] = tp2 - tp1 ;
+ }
+
+#ifndef NDEBUG
+ DEBUG4 (("Reduced IN row:\n")) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ DEBUG6 ((" "ID" "ID" "ID"\n",
+ j, Work->Fcols [j], Fcpos [Work->Fcols [j]])) ;
+ ASSERT (Fcpos [Work->Fcols [j]] >= 0) ;
+ }
+ for (j = fncols ; j < rdeg [IN] ; j++)
+ {
+ DEBUG6 ((" "ID" "ID" "ID"\n", j, W_i [j], Wp [W_i [j]]));
+ ASSERT (Wp [W_i [j]] == wpflag) ;
+ }
+ /* mark the end of the pattern in case we scan it by mistake */
+ /* Note that this means W_i must be of size >= fncols_max + 1 */
+ W_i [rdeg [IN]] = EMPTY ;
+#endif
+
+ /* rdeg [IN] is now the exact degree of the IN row */
+
+ /* clear Work->Wp. All Wp [0..n] is now negative, and */
+ /* greater than Work->wpflag */
+ Work->Wpflag-- ;
+ }
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the candidate row not in the front, if any */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG4 (("pivrow [OUT]: "ID"\n", pivrow [OUT])) ;
+ UMF_dump_rowcol (0, Numeric, Work, pivrow [OUT], TRUE) ;
+#endif
+
+ /* If this is a candidate row from the row merge set, force it to be */
+ /* scanned (ignore prior_pivrow [OUT]). */
+
+ if (pivrow [OUT] != EMPTY)
+ {
+ freebie [OUT] = (pivrow [OUT] == prior_pivrow [OUT]) && cdeg > 0 ;
+ ASSERT (cdeg >= 0) ;
+
+ if (!freebie [OUT])
+ {
+
+ wpflag = Work->Wpflag ;
+ ASSERT (wpflag < EMPTY) ;
+
+ /* -------------------------------------------------------------- */
+ /* construct the pattern of the row */
+ /* -------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ /* check Wp */
+ if (UMF_debug > 0 || MAX (Work->n_row, Work->n_col) < 1000)
+ {
+ for (i = 0 ; i < MAX (Work->n_row, Work->n_col) ; i++)
+ {
+ ASSERT (Wp [i] < 0) ;
+ ASSERT (Wp [i] > wpflag) ;
+ }
+ }
+#endif
+
+ rdeg [OUT] = 0 ;
+
+ ASSERT (pivrow [OUT] >= 0 && pivrow [OUT] < Work->n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (pivrow [OUT])) ;
+
+ /* add the pivot column itself */
+ if (Wp [pivcol] > wpflag)
+ {
+ DEBUG0 (("Adding pivot col to pivrow [OUT] pattern\n")) ;
+ if (rdeg [OUT] >= max_rdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wp [pivcol] = wpflag ;
+ W_o [rdeg [OUT]++] = pivcol ;
+ }
+
+ tpi = Row_tuples [pivrow [OUT]] ;
+ if (tpi)
+ {
+ tp = (Tuple *) (Memory + tpi) ;
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + Row_tlen [pivrow [OUT]] ;
+ 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 ;
+ ncols = ep->ncols ;
+ Rows = Cols + ncols ;
+ if (Rows [f] == EMPTY)
+ {
+ continue ; /* row already assembled */
+ }
+ ASSERT (pivrow [OUT] == Rows [f]) ;
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if ((col >= 0) && (Wp [col] > wpflag))
+ {
+ if (rdeg [OUT] >= max_rdeg)
+ {
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wp [col] = wpflag ;
+ W_o [rdeg [OUT]++] = col ;
+ }
+ }
+
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ Row_tlen [pivrow [OUT]] = tp2 - tp1 ;
+ }
+
+#ifndef NDEBUG
+ DEBUG4 (("Reduced row OUT:\n")) ;
+ for (j = 0 ; j < rdeg [OUT] ; j++)
+ {
+ DEBUG6 ((" "ID" "ID" "ID"\n", j, W_o [j], Wp [W_o [j]])) ;
+ ASSERT (Wp [W_o [j]] == wpflag) ;
+ }
+ /* mark the end of the pattern in case we scan it by mistake */
+ /* Note that this means W_o must be of size >= fncols_max + 1 */
+ W_o [rdeg [OUT]] = EMPTY ;
+#endif
+
+ /* rdeg [OUT] is now the exact degree of the row */
+
+ /* clear Work->Wp. All Wp [0..n] is now negative, and */
+ /* greather than Work->Wpflag */
+ Work->Wpflag-- ;
+ }
+
+ }
+ DEBUG5 (("Row_search end ] \n")) ;
+
+ return (UMFPACK_OK) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_scale_column.c b/src/sparse-matrix/umfpack/umf_scale_column.c
new file mode 100644
index 0000000..2c778a8
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_scale_column.c
@@ -0,0 +1,773 @@
+/* ========================================================================== */
+/* === UMF_scale_column ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Scale the current pivot column, and log the permutation.
+ Store the LU factors. Called by the kernel.
+
+ Returns TRUE if successful, FALSE if out of memory.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_alloc_head_block.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_get_memory.h"
+
+/* ========================================================================== */
+
+GLOBAL Int UMF_scale_column
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, k, k1, fnrows_max, fnrows, fncols, *Frpos, *Fcpos, pos, row, col,
+ pivrow, pivcol, *Frows, *Fcols, *Lpattern, *Upattern, *Lpos, *Upos,
+ llen, ulen, fncols_max, fnpiv, uilen, lnz, unz, *Row_tuples,
+ *Col_tuples, *Rperm, *Cperm, *Lilen, *Uilen, *Lip, *Uip, *Li, *Ui,
+ pivcol_position, newLchain, newUchain, pivrow_position, p, size, lip,
+ uip, lnzi, lnzx, unzx, lnz2i, lnz2x, unz2i, unz2x, zero_pivot,
+ is_nonzero, nan_pivot ;
+ Entry *D, x, pivot_value, *Fx, *Fcol, *Frow, *Lval, *Uval ;
+ double d ;
+
+#ifndef NDEBUG
+ Int *Col_degree, *Row_degree ;
+ UMF_allocfail = FALSE ;
+ if (UMF_gprob > 0) /* a double relop, but ignore NaN case */
+ {
+ double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+ DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+ UMF_allocfail = rrr < UMF_gprob ; /* a double relop, but ignore NaN case */
+ if (UMF_allocfail)
+ {
+ DEBUG1 (("Random garbage collection (scale_column)\n")) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+
+ /* ---------------------------------------------------------------------- */
+
+ Rperm = Numeric->Rperm ;
+ Cperm = Numeric->Cperm ;
+ Lpos = Numeric->Lpos ;
+ Upos = Numeric->Upos ;
+ Lilen = Numeric->Lilen ;
+ Uilen = Numeric->Uilen ;
+
+ Lip = Numeric->Lip ;
+ Uip = Numeric->Uip ;
+ D = Numeric->D ;
+
+ /* ---------------------------------------------------------------------- */
+
+ k = Work->npiv++ ;
+
+ Fx = Work->Fx ;
+ fnrows_max = Work->fnrows_max ;
+ fncols_max = Work->fncols_max ;
+ fnpiv = Work->fnpiv ;
+ Frpos = Work->Frpos ;
+ Fcpos = Work->Fcpos ;
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+ pivrow = Work->pivrow ;
+ pivcol = Work->pivcol ;
+
+ ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+ ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+ ASSERT (k < MIN (Work->n_row, Work->n_col)) ;
+
+#ifndef NDEBUG
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
+ if (k % 1000 == 0) DEBUG0 (("step "ID"\n", k)) ;
+#endif
+
+ Row_tuples = Numeric->Uip ;
+ Col_tuples = Numeric->Lip ;
+
+ Lpattern = Work->Lpattern ;
+ llen = Work->llen ;
+ Upattern = Work->Upattern ;
+ ulen = Work->ulen ;
+
+ /* ---------------------------------------------------------------------- */
+
+ /* Frpos [row] >= 0 for each row in pivot column pattern. */
+ /* offset into pattern is given by: */
+ /* Frpos [row] == offset - 1 */
+ /* Frpos [pivrow] is the offset of the latest pivot row */
+
+ /* Fcpos [col] >= 0 for each col in pivot row pattern. */
+ /* Fcpos [col] == (offset - 1) * fnrows_max */
+ /* Fcpos [pivcol] is the offset of the latest pivot column */
+
+ /* Fcols [0..fncols-1] is the pivot row pattern (excl pivot cols) */
+ /* Frows [0..fnrows-1] is the pivot col pattern (excl pivot rows) */
+
+#ifndef NDEBUG
+ DEBUG7 (("Current frontal matrix: (prior to pivcol scale)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ {
+ Int row, col, i, lcnt, ucnt ;
+
+ DEBUG2 (("Store column of L, k = "ID", llen "ID"\n", k, llen)) ;
+ for (i = 0 ; i < llen ; i++)
+ {
+ row = Lpattern [i] ;
+ ASSERT (row >= 0 && row < Work->n_row) ;
+ DEBUG2 ((" Lpattern["ID"] "ID" Lpos "ID, i, row, Lpos [row])) ;
+ if (row == pivrow) DEBUG2 ((" <- pivot row")) ;
+ DEBUG2 (("\n")) ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ ASSERT (i == Lpos [row]) ;
+ }
+
+ DEBUG2 (("Store row of U, k = "ID", ulen "ID"\n", k, ulen)) ;
+ for (i = 0 ; i < ulen ; i++)
+ {
+ col = Upattern [i] ;
+ DEBUG2 ((" Upattern["ID"] "ID, i, col)) ;
+ if (col == pivcol) DEBUG2 ((" <- pivot col")) ;
+ DEBUG2 (("\n")) ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ ASSERT (i == Upos [col]) ;
+ }
+
+ lcnt = 0 ;
+ ucnt = 0 ;
+ if (Work->n_row < 1000)
+ {
+ for (row = 0 ; row < Work->n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row) && Lpos [row] != EMPTY) lcnt++ ;
+ }
+ ASSERT (lcnt == llen) ;
+ }
+ if (Work->n_col < 1000)
+ {
+ for (col = 0 ; col < Work->n_col ; col++)
+ {
+ if (NON_PIVOTAL_COL (col) && Upos [col] != EMPTY) ucnt++ ;
+ }
+ ASSERT (ucnt == ulen) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* remove pivot row from L */
+ /* ---------------------------------------------------------------------- */
+
+ /* remove pivot row index from current column of L */
+ /* if a new Lchain starts, then all entries are removed later */
+ DEBUG2 (("Removing pivrow from Lpattern, k = "ID"\n", k)) ;
+ ASSERT (NON_PIVOTAL_ROW (pivrow)) ;
+ pivrow_position = Lpos [pivrow] ;
+ if (pivrow_position != EMPTY)
+ {
+ /* place the last entry in the column in the */
+ /* position of the pivot row index */
+ ASSERT (pivrow == Lpattern [pivrow_position]) ;
+ row = Lpattern [--llen] ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ Lpattern [pivrow_position] = row ;
+ Lpos [row] = pivrow_position ;
+ Lpos [pivrow] = EMPTY ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* store the pivot value, for the diagonal matrix D */
+ /* ---------------------------------------------------------------------- */
+
+ /* fnpiv-th pivot in frontal matrix located in */
+ /* Fx (fnrows_max-fnpiv, fncols_max-fnpiv) */
+
+ Fcol = Fx + (fncols_max - fnpiv) * fnrows_max ;
+ pivot_value = Fcol [fnrows_max - fnpiv] ;
+ D [k] = pivot_value ;
+
+ ABS (d, pivot_value) ;
+ zero_pivot = SCALAR_IS_ZERO (d) ;
+ nan_pivot = SCALAR_IS_NAN (d) ;
+
+ if (k == 0)
+ {
+ Numeric->min_udiag = d ;
+ Numeric->max_udiag = d ;
+ }
+ else
+ {
+ /* min (abs (diag (U))) behaves as follows: If any entry is zero,
+ then the result is zero (regardless of the presence of NaN's).
+ Otherwise, if any entry is NaN, then the result is NaN. Otherwise,
+ the result is the smallest absolute value on the diagonal of U.
+ */
+
+ if (SCALAR_IS_NONZERO (Numeric->min_udiag))
+ {
+ if (zero_pivot || nan_pivot)
+ {
+ Numeric->min_udiag = d ;
+ }
+ else if (!SCALAR_IS_NAN (Numeric->min_udiag))
+ {
+ /* d and min_udiag are both non-NaN */
+ Numeric->min_udiag = MIN (Numeric->min_udiag, d) ;
+ }
+ }
+
+ /*
+ max (abs (diag (U))) behaves as follows: If any entry is NaN
+ then the result is NaN. Otherise, the result is the largest
+ absolute value on the diagonal of U.
+ */
+
+ if (nan_pivot)
+ {
+ Numeric->max_udiag = d ;
+ }
+ else if (!SCALAR_IS_NAN (Numeric->max_udiag))
+ {
+ /* d and max_udiag are both non-NaN */
+ Numeric->max_udiag = MAX (Numeric->max_udiag, d) ;
+ }
+ }
+
+ if (!zero_pivot)
+ {
+ /* the pivot is nonzero, but might be Inf or NaN */
+ Numeric->nnzpiv++ ;
+ }
+ DEBUG4 (("Pivot abs value: %g nnzpiv: "ID" D["ID"]=", d, Numeric->nnzpiv, k)) ;
+ EDEBUG4 (pivot_value) ;
+ DEBUG4 (("\n")) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* scale pivot column and count nonzeros in kth column of L */
+ /* ---------------------------------------------------------------------- */
+
+ lnz = 0 ;
+ lnz2i = 0 ;
+ lnz2x = llen ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ EDEBUG4 (Fcol [i]) ;
+ EDEBUG4 (pivot_value) ;
+ if (IS_NONZERO (Fcol [i]))
+ {
+ /* Fcol [i] is nonzero, NaN, or Inf */
+ /* Fcol [i] = Fcol [i] / pivot_value ; */
+ DIV (x, Fcol [i], pivot_value) ;
+ Fcol [i] = x ;
+ /* underflow may have occured, so check if result is zero */
+ is_nonzero = IS_NONZERO (x) ;
+ }
+ else
+ {
+ /* Fcol [i] is zero. Do not divide by pivot value. */
+ is_nonzero = FALSE ;
+ }
+ DEBUG4 (("pivot column: "ID" is_nonzero "ID, i, is_nonzero)) ;
+ EDEBUG4 (Fcol [i]) ;
+ DEBUG4 (("\n")) ;
+
+ /* if we start a new Lchain: */
+ if (is_nonzero)
+ {
+ /* one new integer and one new Entry */
+ DEBUG4 ((" got an entry \n")) ;
+ lnz++ ;
+ }
+
+ /* if we continue the prior Lchain: */
+ row = Frows [i] ;
+ ASSERT (row != pivrow) ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ pos = Lpos [row] ;
+ if (pos == EMPTY && is_nonzero)
+ {
+ /* row is not in the Lpattern, add it if Fcol [i] is nonzero */
+ lnz2i++ ;
+ lnz2x++ ;
+ }
+ DEBUG3 (("Scale L col, row "ID" pos "ID" scaled value", row, pos)) ;
+ EDEBUG3 (Fcol [i]) ;
+ DEBUG3 ((" ::: lnz "ID" lnz2i "ID" lnz2x "ID"\n", lnz, lnz2i, lnz2x)) ;
+ }
+
+ /* determine if we start a new Lchain or continue the old one */
+ if (llen == 0 || zero_pivot)
+ {
+ /* llen == 0 means there is no prior Lchain */
+ /* D [k] == 0 means the pivot column is empty */
+ newLchain = TRUE ;
+ }
+ else
+ {
+ newLchain =
+ /* storage for starting a new Lchain */
+ UNITS (Entry, lnz) + UNITS (Int, lnz)
+ <=
+ /* storage for continuing a prior Lchain */
+ UNITS (Entry, lnz2x) + UNITS (Int, lnz2i) ;
+ }
+
+ if (newLchain)
+ {
+ /* start a new chain for column k of L */
+ DEBUG2 (("Start new Lchain, k = "ID"\n", k)) ;
+
+ pivrow_position = EMPTY ;
+
+ /* clear the prior Lpattern */
+ for (i = 0 ; i < llen ; i++)
+ {
+ row = Lpattern [i] ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ Lpos [row] = EMPTY ;
+ }
+ llen = 0 ;
+
+ lnzi = lnz ;
+ lnzx = lnz ;
+ }
+ else
+ {
+ /* continue the prior Lchain */
+ DEBUG2 (("Continue Lchain, k = "ID"\n", k)) ;
+ lnzi = lnz2i ;
+ lnzx = lnz2x ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* count the nonzeros in the row of U */
+ /* ---------------------------------------------------------------------- */
+
+ /* store the numerical entries and find new nonzeros */
+ Frow = Fx + (fnrows_max - fnpiv) ;
+
+ unz = 0 ;
+ unz2i = 0 ;
+ unz2x = ulen ;
+ DEBUG2 (("unz2x is "ID"\n", unz2x)) ;
+
+ /* if row k does not end a Uchain, pivcol will not be included in ulen */
+
+ ASSERT (NON_PIVOTAL_COL (pivcol)) ;
+ pivcol_position = Upos [pivcol] ;
+ if (pivcol_position != EMPTY)
+ {
+ unz2x-- ;
+ DEBUG2 (("(exclude pivcol) unz2x is now "ID"\n", unz2x)) ;
+ }
+
+ ASSERT (unz2x >= 0) ;
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ x = Frow [i * fnrows_max] ;
+ is_nonzero = IS_NONZERO (x) ;
+
+ /* if we start a new Uchain */
+ if (is_nonzero)
+ {
+ unz++ ;
+ DEBUG2 (("If Unew: "ID, unz)) ;
+ EDEBUG2 (x) ;
+ DEBUG2 (("\n")) ;
+ }
+
+ /* if we continue the prior Uchain */
+ col = Fcols [i] ;
+ ASSERT (col != pivcol) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ pos = Upos [col] ;
+ if (pos == EMPTY && is_nonzero)
+ {
+ /* add this new nonzero entry to the U pattern, if nonzero */
+ unz2i++ ;
+ unz2x++ ;
+ DEBUG2 (("If old: "ID" :", unz2x)) ;
+ EDEBUG2 (x) ;
+ DEBUG2 (("\n")) ;
+ }
+ }
+
+ ASSERT (IMPLIES (k == 0, ulen == 0)) ;
+
+ /* determine if we start a new Uchain or continue the old one */
+ if (ulen == 0 || zero_pivot)
+ {
+ /* ulen == 0 means there is no prior Uchain */
+ /* D [k] == 0 means the matrix is singular (pivot row might */
+ /* not be empty, however, but start a new Uchain to prune zero */
+ /* entries for the deg > 0 test in UMF_u*solve) */
+ newUchain = TRUE ;
+ }
+ else
+ {
+ newUchain =
+ /* approximate storage for starting a new Uchain */
+ UNITS (Entry, unz) + UNITS (Int, unz)
+ <=
+ /* approximate storage for continuing a prior Uchain */
+ UNITS (Entry, unz2x) + UNITS (Int, unz2i) ;
+
+ /* this would be exact, except for the Int to Unit rounding, */
+ /* because the Upattern is stored only at the end of the Uchain */
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate space for the column of L and the row of U */
+ /* ---------------------------------------------------------------------- */
+
+ size = UNITS (Int, lnzi) + UNITS (Entry, lnzx) ;
+ if (newUchain)
+ {
+ /* store the pattern of the last row in the prior Uchain */
+ size += UNITS (Int, ulen) ;
+ unzx = unz ;
+ }
+ else
+ {
+ unzx = unz2x ;
+ }
+ size += UNITS (Entry, unzx) ;
+
+ p = UMF_mem_alloc_head_block (Numeric, size) ;
+ if (!p)
+ {
+ /* do garbage collection, realloc, and try again */
+ if (!UMF_get_memory (Numeric, Work, size))
+ {
+ return (FALSE) ; /* out of memory */
+ }
+ p = UMF_mem_alloc_head_block (Numeric, size) ;
+ }
+ if (!p)
+ {
+ return (FALSE) ; /* out of memory */
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* store the column of L */
+ /* ---------------------------------------------------------------------- */
+
+ lip = p ;
+
+ Li = (Int *) (Numeric->Memory + p) ;
+ p += UNITS (Int, lnzi) ;
+ Lval = (Entry *) (Numeric->Memory + p) ;
+ p += UNITS (Entry, lnzx) ;
+
+ for (i = 0 ; i < lnzx ; i++)
+ {
+ CLEAR (Lval [i]) ;
+ }
+
+ /* store the numerical entries */
+
+ if (newLchain)
+ {
+ /* flag the first column in the Lchain by negating Lip [k] */
+ lip = -lip ;
+
+ ASSERT (llen == 0) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ x = Fcol [i] ;
+ DEBUG4 (("Store column, i "ID" is_nonzero(x) "ID"\n", i,
+ IS_NONZERO (x))) ;
+ EDEBUG4 (x) ;
+ EDEBUG4 (Fcol [i]) ;
+ DEBUG4 (("\n")) ;
+
+ if (IS_NONZERO (x))
+ {
+ DEBUG4 (("Store column, i "ID" is_nonzero(x) "ID"\n", i,
+ IS_NONZERO (x))) ;
+
+ row = Frows [i] ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ pos = llen++ ;
+ Lpattern [pos] = row ;
+ Lpos [row] = pos ;
+ Li [pos] = row ;
+ Lval [pos] = x ;
+ DEBUG2 (("(newLchain) New entry in Lpattern: row "ID" pos "ID
+ "\n", row, pos)) ;
+ DEBUG2 (("(newLchain) Store Lval row "ID" pos "ID" value",
+ row, pos)) ;
+ EDEBUG2 (x) ;
+ DEBUG2 (("\n")) ;
+ }
+ }
+ }
+ else
+ {
+ ASSERT (llen > 0) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ x = Fcol [i] ;
+ if (IS_NONZERO (x))
+ {
+ row = Frows [i] ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ pos = Lpos [row] ;
+ if (pos == EMPTY)
+ {
+ /* add this new nonzero entry to the L pattern */
+ pos = llen++ ;
+ DEBUG2 (("New entry in Lpattern: row "ID" pos "ID"\n",
+ row, pos)) ;
+ ASSERT (llen <= lnzx) ;
+ Lpattern [pos] = row ;
+ Lpos [row] = pos ;
+ *Li++ = row ;
+ }
+ DEBUG2 (("Store Lval row "ID" pos "ID" value", row, pos)) ;
+ EDEBUG2 (x) ;
+ DEBUG2 (("\n")) ;
+ ASSERT (row == Lpattern [pos]) ;
+ ASSERT (pos < lnzx) ;
+ Lval [pos] = x ;
+ }
+ }
+ }
+ DEBUG4 (("llen "ID" lnzx "ID"\n", llen, lnzx)) ;
+ ASSERT (llen == lnzx) ;
+ ASSERT (lnz <= llen) ;
+
+ Numeric->lnz += lnz ;
+ Numeric->nLentries += lnzx ;
+ Work->llen = llen ;
+ Numeric->isize += lnzi ;
+
+ /* ---------------------------------------------------------------------- */
+ /* store the row of U */
+ /* ---------------------------------------------------------------------- */
+
+ uip = p ;
+
+ if (newUchain)
+ {
+ /* starting a new Uchain - flag this by negating Uip [k] */
+ uip = -uip ;
+ DEBUG2 (("Start new Uchain, k = "ID"\n", k)) ;
+
+ pivcol_position = EMPTY ;
+
+ /* end the prior Uchain */
+ /* save the current Upattern, and then */
+ /* clear it and start a new Upattern */
+ DEBUG2 (("Ending prior chain, k-1 = "ID"\n", k-1)) ;
+ uilen = ulen ;
+ Ui = (Int *) (Numeric->Memory + p) ;
+ Numeric->isize += ulen ;
+ p += UNITS (Int, ulen) ;
+ for (i = 0 ; i < ulen ; i++)
+ {
+ col = Upattern [i] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ Upos [col] = EMPTY ;
+ Ui [i] = col ;
+ }
+
+ ulen = 0 ;
+
+ }
+ else
+ {
+ /* continue the prior Uchain */
+ DEBUG2 (("Continue Uchain, k = "ID"\n", k)) ;
+ ASSERT (k > 0) ;
+
+ /* remove pivot col index from current row of U */
+ /* if a new Uchain starts, then all entries are removed later */
+ DEBUG2 (("Removing pivcol from Upattern, k = "ID"\n", k)) ;
+
+ if (pivcol_position != EMPTY)
+ {
+ /* place the last entry in the row in the */
+ /* position of the pivot col index */
+ ASSERT (pivcol == Upattern [pivcol_position]) ;
+ col = Upattern [--ulen] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ Upattern [pivcol_position] = col ;
+ Upos [col] = pivcol_position ;
+ Upos [pivcol] = EMPTY ;
+ }
+
+ /* this row continues the Uchain. Keep track of how much */
+ /* to trim from the k-th length to get the length of the */
+ /* (k-1)st row of U */
+ uilen = unz2i ;
+
+ }
+
+ Uval = (Entry *) (Numeric->Memory + p) ;
+ /* p += UNITS (Entry, unzx), no need to increment p */
+
+ for (i = 0 ; i < unzx ; i++)
+ {
+ CLEAR (Uval [i]) ;
+ }
+
+ if (newUchain)
+ {
+ ASSERT (ulen == 0) ;
+ for (i = 0 ; i < fncols ; i++)
+ {
+ x = Frow [i * fnrows_max] ;
+ if (IS_NONZERO (x))
+ {
+ /* add this new nonzero entry to the U pattern */
+ col = Fcols [i] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ pos = ulen++ ;
+ Upattern [pos] = col ;
+ Upos [col] = pos ;
+ Uval [pos] = x ;
+ DEBUG2 (("(newUchain) New entry in Upattern: col "ID" pos "ID
+ "\n", col, pos)) ;
+ DEBUG2 (("(newUchain) Store Uval col "ID" pos "ID" value",
+ col, pos)) ;
+ EDEBUG2 (x) ;
+ DEBUG2 (("\n")) ;
+ }
+ }
+ }
+ else
+ {
+
+ ASSERT (ulen > 0) ;
+
+ /* store the numerical entries and find new nonzeros */
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ x = Frow [i * fnrows_max] ;
+ if (IS_NONZERO (x))
+ {
+ col = Fcols [i] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ pos = Upos [col] ;
+ if (pos == EMPTY)
+ {
+ /* add this new nonzero entry to the U pattern */
+ ASSERT (ulen < unzx) ;
+ pos = ulen++ ;
+ Upattern [pos] = col ;
+ Upos [col] = pos ;
+ DEBUG2 (("New entry in Upattern: col "ID" pos "ID"\n",
+ col, pos)) ;
+ }
+ DEBUG2 (("Store Uval col "ID" pos "ID" value", col, pos)) ;
+ EDEBUG2 (x) ;
+ DEBUG2 (("\n")) ;
+ ASSERT (col == Upattern [pos]) ;
+ ASSERT (pos < unzx) ;
+ Uval [pos] = x ;
+ }
+ }
+ }
+
+ ASSERT (ulen == unzx) ;
+ ASSERT (unz <= ulen) ;
+ Numeric->unz += unz ;
+ Numeric->nUentries += unzx ;
+ Work->ulen = ulen ;
+ DEBUG1 (("Work->ulen = "ID" at end of pivot step, k: "ID"\n", ulen, k)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* count the "true" flops, based on LU pattern only */
+ /* ---------------------------------------------------------------------- */
+
+ /* the outer product is not done here, but in the BLAS */
+ Numeric->flops += DIV_FLOPS * lnz /* scale pivot column */
+ + MULTSUB_FLOPS * (lnz*unz) ; /* outer product */
+
+ /* ====================================================================== */
+ /* A pivot step is complete */
+ /* ====================================================================== */
+
+#ifndef NDEBUG
+ DEBUG7 (("Current frontal matrix: (after pivcol scale)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* remove pivot row and column from frontal pattern */
+ /* ---------------------------------------------------------------------- */
+
+ Frpos [pivrow] = EMPTY ;
+ Fcpos [pivcol] = EMPTY ;
+
+ /* ---------------------------------------------------------------------- */
+ /* deallocate the pivot row and pivot column tuples */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_mem_free_tail_block (Numeric, Row_tuples [pivrow]) ;
+ UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol]) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* the pivot column is fully assembled and scaled, and is now the */
+ /* k-th column of L. The pivot row is the k-th row of U. */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG5 (("number of pivots prior to this one: "ID"\n", k)) ;
+ ASSERT (NON_PIVOTAL_ROW (pivrow)) ;
+ ASSERT (NON_PIVOTAL_COL (pivcol)) ;
+
+ /* save row and column inverse permutation */
+ k1 = ONES_COMPLEMENT (k) ;
+ Rperm [pivrow] = k1 ; /* aliased with Row_degree */
+ Cperm [pivcol] = k1 ; /* aliased with Col_degree */
+
+ ASSERT (!NON_PIVOTAL_ROW (pivrow)) ;
+ ASSERT (!NON_PIVOTAL_COL (pivcol)) ;
+
+ Lpos [pivrow] = pivrow_position ;
+ Upos [pivcol] = pivcol_position ;
+
+ Lip [pivcol] = lip ; /* aliased with Col_tuples */
+ Lilen [pivcol] = lnzi ; /* aliased with Col_tlen */
+
+ Uip [pivrow] = uip ; /* aliased with Row_tuples */
+ Uilen [pivrow] = uilen ; /* aliased with Row_tlen */
+
+ return (TRUE) ;
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_set_stats.c b/src/sparse-matrix/umfpack/umf_set_stats.c
new file mode 100644
index 0000000..6497b4d
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_set_stats.c
@@ -0,0 +1,109 @@
+/* ========================================================================== */
+/* === UMF_set_stats ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Sets statistics in Info array. Calculates everything in double precision,
+ rather than Int or size_t, so that usage estimates can be computed even if
+ the problem is so large that it would cause integer overflow.
+
+ This routine has many double relop's, but the NaN case is ignored.
+*/
+
+#include "umf_internal.h"
+#include "umf_symbolic_usage.h"
+
+GLOBAL void UMF_set_stats
+(
+ double Info [ ],
+ SymbolicType *Symbolic,
+ double max_usage, /* peak size of Numeric->Memory, in Units */
+ double num_mem_size, /* final size of Numeric->Memory, in Units */
+ double flops, /* "true flops" */
+ double lnz, /* nz in L */
+ double unz, /* nz in U */
+ double maxfrsize, /* largest front size */
+ double ulen, /* size of Numeric->Upattern */
+ double npiv, /* number of pivots found */
+ Int what /* ESTIMATE or ACTUAL */
+)
+{
+
+ double sym_size, work_usage, nn, n_row, n_col, n_inner, num_On_size1,
+ num_On_size2, num_usage, maxncols, maxnrows ;
+
+ n_col = Symbolic->n_col ;
+ n_row = Symbolic->n_row ;
+ nn = MAX (n_row, n_col) ;
+ n_inner = MIN (n_row, n_col) ;
+ maxncols = Symbolic->maxncols ;
+ maxnrows = Symbolic->maxnrows ;
+
+ /* final Symbolic object size */
+ sym_size = UMF_symbolic_usage (Symbolic->n_row, Symbolic->n_col,
+ Symbolic->nchains, Symbolic->nfr) ;
+
+ /* size of O(n) part of Numeric object during factorization, */
+ /* except Numeric->Memory and Numeric->Upattern */
+ num_On_size1 =
+ DUNITS (NumericType, 1) /* Numeric structure */
+ + DUNITS (Entry, n_inner+1) /* D */
+ + 4 * DUNITS (Int, n_row+1) /* Rperm, Lpos, Uilen, Uip */
+ + 4 * DUNITS (Int, n_col+1) ; /* Cperm, Upos, Lilen, Lip */
+
+ /* size of O(n) part of Numeric object after factorization, */
+ /* except Numeric->Memory and Numeric->Upattern */
+ num_On_size2 =
+ DUNITS (NumericType, 1) /* Numeric structure */
+ + DUNITS (Entry, n_inner+1) /* D */
+ + DUNITS (Int, n_row+1) /* Rperm */
+ + DUNITS (Int, n_col+1) /* Cperm */
+ + 4 * DUNITS (Int, npiv+1) ; /* Lpos, Uilen, Uip, Upos, Lilen, Lip */
+
+ /* peak size of Numeric->Memory */
+ Info [UMFPACK_VARIABLE_PEAK + what] = max_usage ;
+
+ /* final size of Numeric->Memory */
+ Info [UMFPACK_VARIABLE_FINAL + what] = num_mem_size ;
+
+ /* final size of Numeric object, including Numeric->Memory and ->Upattern */
+ Info [UMFPACK_NUMERIC_SIZE + what] =
+ num_On_size2
+ + num_mem_size /* final Numeric->Memory size */
+ + DUNITS (Int, ulen) ; /* Numeric->Upattern (from Work->Upattern) */
+
+ /* largest front size (Work->Fx size, or actual size used) */
+ Info [UMFPACK_MAX_FRONT_SIZE + what] = maxfrsize ;
+
+ /* UMF_kernel work usage */
+ work_usage =
+ /* Work-> arrays */
+ DUNITS (Entry, Symbolic->maxfrsize) /* Fx */
+ + 2 * DUNITS (Int, n_row+1) /* Frpos, Lpattern */
+ + 2 * DUNITS (Int, n_col+1) /* Fcpos, Upattern */
+ + DUNITS (Int, n_col+n_inner+1) /* E */
+ + DUNITS (Int, nn + 1) /* Wp */
+ + 3 * DUNITS (Int, maxncols + 1) /* Fcols, Wio, Woi */
+ + 2 * DUNITS (Int, maxnrows + 1) /* Frows, Wm */
+ + DUNITS (Int, MAX (maxnrows, maxncols) + 1) /* Woo */
+ + DUNITS (Int, Symbolic->nfr + 1) ; /* Front_new1strow */
+
+ /* Peak memory for just UMFPACK_numeric. This excludes Numeric->Upattern */
+ /* since it includes the equivalenced Work->Upattern array. */
+ num_usage = sym_size + num_On_size1 + work_usage + max_usage ;
+
+ /* peak memory usage for both UMFPACK_*symbolic and UMFPACK_numeric. */
+ Info [UMFPACK_PEAK_MEMORY + what] =
+ MAX (Symbolic->peak_sym_usage, num_usage) ;
+
+ Info [UMFPACK_FLOPS + what] = flops ;
+ Info [UMFPACK_LNZ + what] = lnz ;
+ Info [UMFPACK_UNZ + what] = unz ;
+}
diff --git a/src/sparse-matrix/umfpack/umf_solve.c b/src/sparse-matrix/umfpack/umf_solve.c
new file mode 100644
index 0000000..c16d8c3
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_solve.c
@@ -0,0 +1,1024 @@
+/* ========================================================================== */
+/* === UMF_solve ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Not user-callable. Solves a linear system using the numerical factorization
+ computed by UMFPACK_numeric. No workspace is dynamically allocated. Counts
+ flops, but excludes floating-point comparisons (thus real abs (...) are
+ zero flops, but complex abs (...) takes 6 flops).
+
+ Returns UMFPACK_OK if successful, UMFPACK_ERROR_argument_missing if
+ required arguments are missing, UMFPACK_ERROR_invalid_system if the sys
+ string is not valid or if the matrix A is not square.
+
+ Uses the sparse backward error method of Arioli, Demmel, and Duff
+ (Solving sparse linear systems with sparse backward error, SIAM J. Matrix
+ Analysis and Applic., vol 10, pp. 165-190).
+*/
+
+#include "umf_internal.h"
+#include "umf_lsolve.h"
+#include "umf_usolve.h"
+#include "umf_ltsolve.h"
+#include "umf_utsolve.h"
+
+PRIVATE Int do_step
+(
+ double omega [3],
+ Int step,
+ const double B2 [ ],
+ Entry X [ ],
+ const Entry W [ ],
+ const double Y [ ],
+ const double Z2 [ ],
+ Entry S [ ],
+ Int n,
+ double Info [UMFPACK_INFO]
+) ;
+
+/* ========================================================================== */
+/* === UMF_solve ============================================================ */
+/* ========================================================================== */
+
+GLOBAL Int UMF_solve
+(
+ Int sys,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+ double Xx [ ],
+ const double Bx [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+ double Xz [ ],
+ const double Bz [ ],
+#endif
+ NumericType *Numeric,
+ Int irstep,
+ double Info [UMFPACK_INFO],
+ Int Pattern [ ], /* size n */
+ double SolveWork [ ] /* if irstep>0 real: size 5*n. complex:10*n */
+ /* otherwise real: size n. complex: 4*n */
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int *Rperm, *Cperm, i, n, p, step, j, nz, status ;
+ Entry axx, wi, xj, zi, xi, aij, *W, *Z, *S, *X, bi ;
+ double omega [3], d, *Z2, *Y, z2i, yi, *B2 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initializations */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ UMF_dump_lu (Numeric) ;
+ ASSERT (Numeric && Xx && Bx && Pattern && SolveWork && Info) ;
+#ifdef COMPLEX
+ ASSERT (Xz && Bz) ;
+#endif
+#endif
+
+ nz = 0 ;
+ omega [0] = 0. ;
+ omega [1] = 0. ;
+ omega [2] = 0. ;
+ Rperm = Numeric->Rperm ;
+ Cperm = Numeric->Cperm ;
+ Info [UMFPACK_SOLVE_FLOPS] = 0. ;
+ Info [UMFPACK_IR_TAKEN] = 0 ;
+ Info [UMFPACK_IR_ATTEMPTED] = 0 ;
+
+ /* UMFPACK_solve does not call this routine if A is rectangular */
+ ASSERT (Numeric->n_row == Numeric->n_col) ;
+ n = Numeric->n_row ;
+ if (Numeric->nnzpiv < n
+ || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+ {
+ /* Note that systems involving just L return UMFPACK_OK, even if */
+ /* A is singular (L is always has a unit diagonal). */
+ DEBUG0 (("Warning, matrix is singular in umf_solve\n")) ;
+ status = UMFPACK_WARNING_singular_matrix ;
+ irstep = 0 ;
+ }
+ else
+ {
+ status = UMFPACK_OK ;
+ }
+ irstep = MAX (0, irstep) ; /* make sure irstep is >= 0 */
+
+ W = (Entry *) SolveWork ; /* Entry W [0..n-1] */
+
+ Z = (Entry *) NULL ; /* unused if no iterative refinement */
+ S = (Entry *) NULL ;
+ Y = (double *) NULL ;
+ Z2 = (double *) NULL ;
+ B2 = (double *) NULL ;
+
+#ifdef COMPLEX
+ X = (Entry *) (SolveWork + 2*n) ; /* Entry X [0..n-1] */
+ if (irstep > 0)
+ {
+ if (!Ap || !Ai || !Ax || !Az)
+ {
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+ Z = (Entry *) (SolveWork + 4*n) ; /* Entry Z [0..n-1] */
+ S = (Entry *) (SolveWork + 6*n) ; /* Entry S [0..n-1] */
+ Y = (double *) (SolveWork + 8*n) ; /* double Y [0..n-1] */
+ B2 = (double *) (SolveWork + 9*n) ; /* double B2 [0..n-1] */
+ Z2 = (double *) Z ; /* double Z2 [0..n-1], equiv. to Z */
+ }
+#else
+ X = (Entry *) Xx ; /* Entry X [0..n-1] */
+ if (irstep > 0)
+ {
+ if (!Ap || !Ai || !Ax)
+ {
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+ Z = (Entry *) (SolveWork + n) ; /* Entry Z [0..n-1] */
+ S = (Entry *) (SolveWork + 2*n) ; /* Entry S [0..n-1] */
+ Y = (double *) (SolveWork + 3*n) ; /* double Y [0..n-1] */
+ B2 = (double *) (SolveWork + 4*n) ; /* double B2 [0..n-1] */
+ Z2 = (double *) Z ; /* double Z2 [0..n-1], equiv. to Z */
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* determine which system to solve */
+ /* ---------------------------------------------------------------------- */
+
+ if (sys == UMFPACK_A)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* solve Ax=b with optional iterative refinement */
+ /* ------------------------------------------------------------------ */
+
+ if (irstep > 0)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* using iterative refinement: compute Y and B2 */
+ /* -------------------------------------------------------------- */
+
+ nz = Ap [n] ;
+ Info [UMFPACK_NZ] = nz ;
+
+ /* A is stored by column */
+ /* Y (i) = ||A_i||, 1-norm of row i of A */
+ for (i = 0 ; i < n ; i++)
+ {
+ Y [i] = 0. ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] += (ABS_FLOPS + 1) * nz ;
+ for (j = 0 ; j < n ; j++)
+ {
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ /* Y [Ai [p]] += ABS (Ax [p]) ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ Y [Ai [p]] += d ;
+ }
+ }
+
+ /* B2 = abs (B) */
+ Info [UMFPACK_SOLVE_FLOPS] += ABS_FLOPS * n ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* B2 [i] = ABS (B [i]) ; */
+ ASSIGN (bi, Bx [i], Bz [i]) ;
+ ABS (B2 [i], bi) ;
+ }
+
+ }
+
+ for (step = 0 ; step <= irstep ; step++)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* Solve Ax=b (step 0): */
+ /* x = Q (U \ (L \ (Pb))) */
+ /* and then perform iterative refinement (step > 0): */
+ /* x = x + Q (U \ (L \ (P (b-Ax)))) */
+ /* -------------------------------------------------------------- */
+
+ if (step == 0)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [Rperm [i]] ; */
+ ASSIGN (W [i], Bx [Rperm [i]], Bz [Rperm [i]]) ;
+ }
+ }
+ else
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ /* Z [i] = B [i] ; */
+ ASSIGN (Z [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] += MULTSUB_FLOPS * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ xi = X [i] ;
+ for (p = Ap [i] ; p < Ap [i+1] ; p++)
+ {
+ /* Z [Ai [p]] -= Ax [p] * xi ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT_SUB (Z [Ai [p]], aij, xi) ;
+ }
+ }
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Z [Rperm [i]] ;
+ }
+ }
+ Info [UMFPACK_SOLVE_FLOPS] += UMF_lsolve (Numeric, W, Pattern) ;
+ Info [UMFPACK_SOLVE_FLOPS] += UMF_usolve (Numeric, W, Pattern) ;
+ if (step == 0)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Cperm [i]] = W [i] ;
+ }
+ }
+ else
+ {
+ Info [UMFPACK_SOLVE_FLOPS] += ASSEMBLE_FLOPS * n ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [Cperm [i]] += W [i] ; */
+ ASSEMBLE (X [Cperm [i]], W [i]) ;
+ }
+ }
+
+ /* -------------------------------------------------------------- */
+ /* sparse backward error estimate */
+ /* -------------------------------------------------------------- */
+
+ if (irstep > 0)
+ {
+
+ /* ---------------------------------------------------------- */
+ /* A is stored by column */
+ /* W (i) = (b-Ax)_i, residual */
+ /* Z2 (i) = (|A||x|)_i */
+ /* ---------------------------------------------------------- */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [i] ; */
+ ASSIGN (W [i], Bx [i], Bz [i]) ;
+ Z2 [i] = 0. ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] +=
+ (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+ for (j = 0 ; j < n ; j++)
+ {
+ xj = X [j] ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+
+ /* axx = Ax [p] * xj ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT (axx, aij, xj) ;
+
+ /* W [i] -= axx ; */
+ DECREMENT (W [i], axx) ;
+
+ /* Z2 [i] += ABS (axx) ; */
+ ABS (d, axx) ;
+ Z2 [i] += d ;
+ }
+ }
+
+ if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+ {
+ /* iterative refinement is done */
+ break ;
+ }
+
+ }
+
+ }
+
+ }
+ else if (sys == UMFPACK_At)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* solve A'x=b with optional iterative refinement */
+ /* ------------------------------------------------------------------ */
+
+ /* A' is the complex conjugate transpose */
+
+ if (irstep > 0)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* using iterative refinement: compute Y */
+ /* -------------------------------------------------------------- */
+
+ nz = Ap [n] ;
+ Info [UMFPACK_NZ] = nz ;
+
+ /* A' is stored by row */
+ /* Y (i) = ||A'_i||, 1-norm of row i of A' */
+ Info [UMFPACK_SOLVE_FLOPS] += (ABS_FLOPS + 1) * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ for (p = Ap [i] ; p < Ap [i+1] ; p++)
+ {
+ /* yi += ABS (Ax [p]) ; */
+ /* note that abs (aij) is the same as abs (conj (aij)) */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ yi += d ;
+ }
+ Y [i] = yi ;
+ }
+
+ /* B2 = abs (B) */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* B2 [i] = ABS (B [i]) ; */
+ ASSIGN (bi, Bx [i], Bz [i]) ;
+ ABS (B2 [i], bi) ;
+ }
+
+ }
+
+ for (step = 0 ; step <= irstep ; step++)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* Solve A'x=b (step 0): */
+ /* x = P' (L' \ (U' \ (Q'b))) */
+ /* and then perform iterative refinement (step > 0): */
+ /* x = x + P' (L' \ (U' \ (Q' (b-A'x)))) */
+ /* -------------------------------------------------------------- */
+
+ if (step == 0)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [Cperm [i]] ; */
+ ASSIGN (W [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+ }
+ }
+ else
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ /* Z [i] = B [i] ; */
+ ASSIGN (Z [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] += MULTSUB_FLOPS * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ zi = Z [i] ;
+ for (p = Ap [i] ; p < Ap [i+1] ; p++)
+ {
+ /* zi -= conjugate (Ax [p]) * X [Ai [p]] ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT_SUB_CONJ (zi, X [Ai [p]], aij) ;
+ }
+ Z [i] = zi ;
+ }
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Z [Cperm [i]] ;
+ }
+ }
+ Info [UMFPACK_SOLVE_FLOPS] += UMF_uhsolve (Numeric, W, Pattern) ;
+ Info [UMFPACK_SOLVE_FLOPS] += UMF_lhsolve (Numeric, W, Pattern) ;
+ if (step == 0)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Rperm [i]] = W [i] ;
+ }
+ }
+ else
+ {
+ Info [UMFPACK_SOLVE_FLOPS] += ASSEMBLE_FLOPS * n ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [Rperm [i]] += W [i] ; */
+ ASSEMBLE (X [Rperm [i]], W [i]) ;
+ }
+ }
+
+ /* -------------------------------------------------------------- */
+ /* sparse backward error estimate */
+ /* -------------------------------------------------------------- */
+
+ if (irstep > 0)
+ {
+
+ /* ---------------------------------------------------------- */
+ /* A' is stored by row */
+ /* W (i) = (b-A'x)_i, residual */
+ /* Z (i) = (|A'||x|)_i */
+ /* ---------------------------------------------------------- */
+
+ Info [UMFPACK_SOLVE_FLOPS] +=
+ (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* wi = B [i] ; */
+ ASSIGN (wi, Bx [i], Bz [i]) ;
+ z2i = 0. ;
+ for (p = Ap [i] ; p < Ap [i+1] ; p++)
+ {
+ /* axx = conjugate (Ax [p]) * X [Ai [p]] ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT_CONJ (axx, X [Ai [p]], aij) ;
+
+ /* wi -= axx ; */
+ DECREMENT (wi, axx) ;
+
+ /* z2i += ABS (axx) ; */
+ ABS (d, axx) ;
+ z2i += d ;
+ }
+ W [i] = wi ;
+ Z2 [i] = z2i ;
+ }
+
+ if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+ {
+ /* iterative refinement is done */
+ break ;
+ }
+
+ }
+
+ }
+
+ }
+ else if (sys == UMFPACK_Aat)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* solve A.'x=b with optional iterative refinement */
+ /* ------------------------------------------------------------------ */
+
+ /* A' is the array transpose */
+
+ if (irstep > 0)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* using iterative refinement: compute Y */
+ /* -------------------------------------------------------------- */
+
+ nz = Ap [n] ;
+ Info [UMFPACK_NZ] = nz ;
+
+ /* A.' is stored by row */
+ /* Y (i) = ||A.'_i||, 1-norm of row i of A.' */
+ Info [UMFPACK_SOLVE_FLOPS] += (ABS_FLOPS + 1) * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ for (p = Ap [i] ; p < Ap [i+1] ; p++)
+ {
+ /* yi += ABS (Ax [p]) ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ yi += d ;
+ }
+ Y [i] = yi ;
+ }
+
+ /* B2 = abs (B) */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* B2 [i] = ABS (B [i]) ; */
+ ASSIGN (bi, Bx [i], Bz [i]) ;
+ ABS (B2 [i], bi) ;
+ }
+
+ }
+
+ for (step = 0 ; step <= irstep ; step++)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* Solve A.'x=b (step 0): */
+ /* x = P' (L.' \ (U.' \ (Q'b))) */
+ /* and then perform iterative refinement (step > 0): */
+ /* x = x + P' (L.' \ (U.' \ (Q' (b-A.'x)))) */
+ /* -------------------------------------------------------------- */
+
+ if (step == 0)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [Cperm [i]] ; */
+ ASSIGN (W [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+ }
+ }
+ else
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ /* Z [i] = B [i] ; */
+ ASSIGN (Z [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] += MULTSUB_FLOPS * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ zi = Z [i] ;
+ for (p = Ap [i] ; p < Ap [i+1] ; p++)
+ {
+ /* zi -= Ax [p] * X [Ai [p]] ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT_SUB (zi, aij, X [Ai [p]]) ;
+ }
+ Z [i] = zi ;
+ }
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Z [Cperm [i]] ;
+ }
+ }
+ Info [UMFPACK_SOLVE_FLOPS] += UMF_utsolve (Numeric, W, Pattern) ;
+ Info [UMFPACK_SOLVE_FLOPS] += UMF_ltsolve (Numeric, W, Pattern) ;
+ if (step == 0)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Rperm [i]] = W [i] ;
+ }
+ }
+ else
+ {
+ Info [UMFPACK_SOLVE_FLOPS] += ASSEMBLE_FLOPS * n ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [Rperm [i]] += W [i] ; */
+ ASSEMBLE (X [Rperm [i]], W [i]) ;
+ }
+ }
+
+ /* -------------------------------------------------------------- */
+ /* sparse backward error estimate */
+ /* -------------------------------------------------------------- */
+
+ if (irstep > 0)
+ {
+
+ /* ---------------------------------------------------------- */
+ /* A.' is stored by row */
+ /* W (i) = (b-A.'x)_i, residual */
+ /* Z (i) = (|A.'||x|)_i */
+ /* ---------------------------------------------------------- */
+
+ Info [UMFPACK_SOLVE_FLOPS] +=
+ (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* wi = B [i] ; */
+ ASSIGN (wi, Bx [i], Bz [i]) ;
+ z2i = 0. ;
+ for (p = Ap [i] ; p < Ap [i+1] ; p++)
+ {
+ /* axx = Ax [p] * X [Ai [p]] ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT (axx, aij, X [Ai [p]]) ;
+
+ /* wi -= axx ; */
+ DECREMENT (wi, axx) ;
+
+ /* z2i += ABS (axx) ; */
+ ABS (d, axx) ;
+ z2i += d ;
+ }
+ W [i] = wi ;
+ Z2 [i] = z2i ;
+ }
+
+ if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info))
+ {
+ /* iterative refinement is done */
+ break ;
+ }
+
+ }
+
+ }
+
+ }
+ else if (sys == UMFPACK_Pt_L)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve P'Lx=b: x = L \ Pb */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [Rperm [i]] ; */
+ ASSIGN (X [i], Bx [Rperm [i]], Bz [Rperm [i]]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_lsolve (Numeric, X, Pattern) ;
+ status = UMFPACK_OK ;
+
+ }
+ else if (sys == UMFPACK_L)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve Lx=b: x = L \ b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [i] ; */
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_lsolve (Numeric, X, Pattern) ;
+ status = UMFPACK_OK ;
+
+ }
+ else if (sys == UMFPACK_Lt_P)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve L'Px=b: x = P' (L' \ b) */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [i] ; */
+ ASSIGN (W [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_lhsolve (Numeric, W, Pattern) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Rperm [i]] = W [i] ;
+ }
+ status = UMFPACK_OK ;
+
+ }
+ else if (sys == UMFPACK_Lat_P)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve L.'Px=b: x = P' (L.' \ b) */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [i] ; */
+ ASSIGN (W [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_ltsolve (Numeric, W, Pattern) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Rperm [i]] = W [i] ;
+ }
+ status = UMFPACK_OK ;
+
+ }
+ else if (sys == UMFPACK_Lt)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve L'x=b: x = L' \ b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [i] ; */
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_lhsolve (Numeric, X, Pattern) ;
+ status = UMFPACK_OK ;
+
+ }
+ else if (sys == UMFPACK_Lat)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve L.'x=b: x = L.' \ b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [i] ; */
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_ltsolve (Numeric, X, Pattern) ;
+ status = UMFPACK_OK ;
+
+ }
+ else if (sys == UMFPACK_U_Qt)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve UQ'x=b: x = Q (U \ b) */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [i] ; */
+ ASSIGN (W [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_usolve (Numeric, W, Pattern) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Cperm [i]] = W [i] ;
+ }
+
+ }
+ else if (sys == UMFPACK_U)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve Ux=b: x = U \ b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [i] ; */
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_usolve (Numeric, X, Pattern) ;
+
+ }
+ else if (sys == UMFPACK_Q_Ut)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve QU'x=b: x = U' \ Q'b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [Cperm [i]] ; */
+ ASSIGN (X [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_uhsolve (Numeric, X, Pattern) ;
+
+ }
+ else if (sys == UMFPACK_Q_Uat)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve QU.'x=b: x = U.' \ Q'b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [Cperm [i]] ; */
+ ASSIGN (X [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_utsolve (Numeric, X, Pattern) ;
+
+ }
+ else if (sys == UMFPACK_Ut)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve U'x=b: x = U' \ b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [i] ; */
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_uhsolve (Numeric, X, Pattern) ;
+
+ }
+ else if (sys == UMFPACK_Uat)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* Solve U'x=b: x = U' \ b */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] = B [i] ; */
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ }
+ Info [UMFPACK_SOLVE_FLOPS] = UMF_utsolve (Numeric, X, Pattern) ;
+
+ }
+ else
+ {
+ return (UMFPACK_ERROR_invalid_system) ;
+ }
+
+#ifdef COMPLEX
+ /* copy the solution back, from Entry X [ ] to double Xx [ ]and Xz [ ]*/
+ for (i = 0 ; i < n ; i++)
+ {
+ Xx [i] = REAL_COMPONENT (X [i]) ;
+ Xz [i] = IMAG_COMPONENT (X [i]) ;
+ }
+#endif
+
+ /* return UMFPACK_OK, or UMFPACK_WARNING_singular_matrix */
+ /* Note that systems involving just L will return UMFPACK_OK */
+ return (status) ;
+}
+
+
+/* ========================================================================== */
+/* === do_step ============================================================== */
+/* ========================================================================== */
+
+/* Perform one step of iterative refinement, for Ax=b or A'x=b */
+
+PRIVATE Int do_step /* return TRUE if iterative refinement done */
+(
+ double omega [3],
+ Int step, /* which step of iterative refinement to do */
+ const double B2 [ ], /* abs (B) */
+ Entry X [ ],
+ const Entry W [ ],
+ const double Y [ ],
+ const double Z2 [ ],
+ Entry S [ ],
+ Int n,
+ double Info [UMFPACK_INFO]
+)
+{
+ double last_omega [3], tau, nctau, d1, wd1, d2, wd2, xi, yix, wi, xnorm ;
+ Int i ;
+
+ /* DBL_EPSILON is a standard ANSI C term defined in <float.h> */
+ /* It is the smallest positive x such that 1.0+x != 1.0 */
+
+ nctau = 1000 * n * DBL_EPSILON ;
+ DEBUG0 (("nctau = %30.20e\n", nctau)) ;
+
+ /* for approximate flop count, assume d1 > tau is always true */
+ Info [UMFPACK_SOLVE_FLOPS] += (2*ABS_FLOPS + 5) * n ;
+
+ /* ---------------------------------------------------------------------- */
+ /* save the last iteration in case we need to reinstate it */
+ /* ---------------------------------------------------------------------- */
+
+ last_omega [0] = omega [0] ;
+ last_omega [1] = omega [1] ;
+ last_omega [2] = omega [2] ;
+
+ /* ---------------------------------------------------------------------- */
+ /* compute sparse backward errors: omega [1] and omega [2] */
+ /* ---------------------------------------------------------------------- */
+
+ /* xnorm = ||x|| maxnorm */
+ xnorm = 0.0 ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* xi = ABS (X [i]) ; */
+ ABS (xi, X [i]) ;
+ if (SCALAR_IS_NAN (xi))
+ {
+ xnorm = xi ;
+ break ;
+ }
+ /* no NaN's to consider here: */
+ xnorm = MAX (xnorm, xi) ;
+ }
+
+ omega [1] = 0. ;
+ omega [2] = 0. ;
+ for (i = 0 ; i < n ; i++)
+ {
+ yix = Y [i] * xnorm ;
+ tau = (yix + B2 [i]) * nctau ;
+ d1 = Z2 [i] + B2 [i] ;
+ /* wi = ABS (W [i]) ; */
+ ABS (wi, W [i]) ;
+ if (SCALAR_IS_NAN (d1))
+ {
+ omega [1] = d1 ;
+ omega [2] = d1 ;
+ break ;
+ }
+ if (SCALAR_IS_NAN (tau))
+ {
+ omega [1] = tau ;
+ omega [2] = tau ;
+ break ;
+ }
+ if (d1 > tau) /* a double relop, but no NaN's here */
+ {
+ wd1 = wi / d1 ;
+ if (SCALAR_IS_NAN (wd1))
+ {
+ omega [1] = wd1 ;
+ break ;
+ }
+ /* no NaN's to consider here: */
+ omega [1] = MAX (omega [1], wd1) ;
+ }
+ else if (tau > 0.0) /* a double relop, but no NaN's here */
+ {
+ d2 = Z2 [i] + yix ;
+ wd2 = wi / d2 ;
+ if (SCALAR_IS_NAN (wd2))
+ {
+ omega [2] = wd2 ;
+ break ;
+ }
+ /* no NaN's to consider here: */
+ omega [2] = MAX (omega [2], wd2) ;
+ }
+ }
+
+ omega [0] = omega [1] + omega [2] ;
+ Info [UMFPACK_OMEGA1] = omega [1] ;
+ Info [UMFPACK_OMEGA2] = omega [2] ;
+
+ /* ---------------------------------------------------------------------- */
+ /* stop the iterations if the backward error is small, or NaN */
+ /* ---------------------------------------------------------------------- */
+
+ Info [UMFPACK_IR_TAKEN] = step ;
+ Info [UMFPACK_IR_ATTEMPTED] = step ;
+
+ if (SCALAR_IS_NAN (omega [0]))
+ {
+ DEBUG0 (("omega[0] is NaN - done.\n")) ;
+ if (step > 0)
+ {
+ DEBUG0 (("last iteration better\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ X [i] = S [i] ;
+ }
+ Info [UMFPACK_OMEGA1] = last_omega [1] ;
+ Info [UMFPACK_OMEGA2] = last_omega [2] ;
+ Info [UMFPACK_IR_TAKEN] = step - 1 ;
+ }
+ return (TRUE) ;
+ }
+
+ if (omega [0] < DBL_EPSILON) /* double relop, but no NaN case here */
+ {
+ DEBUG0 (("omega[0] too small - done.\n")) ;
+ return (TRUE) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* stop if insufficient decrease in omega */
+ /* ---------------------------------------------------------------------- */
+
+ /* double relop, but no NaN case here: */
+ if (step > 0 && omega [0] > last_omega [0] / 2)
+ {
+ DEBUG0 (("stop refinement\n")) ;
+ if (omega [0] > last_omega [0])
+ {
+ /* last iteration better than this one, reinstate it */
+ DEBUG0 (("last iteration better\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ X [i] = S [i] ;
+ }
+ Info [UMFPACK_OMEGA1] = last_omega [1] ;
+ Info [UMFPACK_OMEGA2] = last_omega [2] ;
+ }
+ Info [UMFPACK_IR_TAKEN] = step - 1 ;
+ return (TRUE) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* save current solution in case we need to reinstate */
+ /* ---------------------------------------------------------------------- */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ S [i] = X [i] ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* iterative refinement continues */
+ /* ---------------------------------------------------------------------- */
+
+ return (FALSE) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_symbolic_usage.c b/src/sparse-matrix/umfpack/umf_symbolic_usage.c
new file mode 100644
index 0000000..a9b25ba
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_symbolic_usage.c
@@ -0,0 +1,33 @@
+/* ========================================================================== */
+/* === UMF_symbolic_usage =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Returns the final size of the Symbolic object, in Units */
+
+#include "umf_internal.h"
+
+GLOBAL double UMF_symbolic_usage
+(
+ Int n_row,
+ Int n_col,
+ Int nchains,
+ Int nfr
+)
+{
+ double units =
+ DUNITS (SymbolicType, 1) /* Symbolic structure */
+ + DUNITS (Int, n_col+1) /* Cperm_init */
+ + DUNITS (Int, n_row+1) /* Rperm_init */
+ + 3*DUNITS (Int, nchains+1) /* Chain_ */
+ + 4*DUNITS (Int, nfr+1) ; /* Front_ */
+
+ return (units) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_transpose.c b/src/sparse-matrix/umfpack/umf_transpose.c
new file mode 100644
index 0000000..1b23aa7
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_transpose.c
@@ -0,0 +1,385 @@
+/* ========================================================================== */
+/* === UMF_transpose ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Not user-callable. Computes a permuted transpose, R = (A (P,Q(1:nq)))' in
+ MATLAB notation, where R is in column-form. A is n_row-by-n_col, the
+ row-form matrix R is n_row-by-nq, where nq <= n_col. A may be singular.
+ The complex version can do transpose (') or array transpose (.').
+
+ Uses Gustavson's method (Two Fast Algorithms for Sparse Matrices:
+ Multiplication and Permuted Transposition, ACM Trans. on Math. Softw.,
+ vol 4, no 3, pp. 250-269).
+*/
+
+#include "umf_internal.h"
+#include "umf_is_permutation.h"
+
+/* ========================================================================== */
+
+GLOBAL Int UMF_transpose
+(
+ Int n_row, /* A is n_row-by-n_col */
+ Int n_col,
+ const Int Ap [ ], /* size n_col+1 */
+ const Int Ai [ ], /* size nz = Ap [n_col] */
+ const double Ax [ ], /* size nz if present */
+
+ const Int P [ ], /* P [k] = i means original row i is kth row in A(P,Q)*/
+ /* P is identity if not present */
+ /* size n_row, if present */
+
+ const Int Q [ ], /* Q [k] = j means original col j is kth col in A(P,Q)*/
+ /* Q is identity if not present */
+ /* size nq, if present */
+ Int nq, /* size of Q, ignored if Q is (Int *) NULL */
+
+ /* output matrix: Rp, Ri, Rx, and Rz: */
+ Int Rp [ ], /* size n_row+1 */
+ Int Ri [ ], /* size nz */
+ double Rx [ ], /* size nz, if present */
+
+ Int W [ ], /* size max (n_row,n_col) workspace */
+
+ Int check /* if true, then check inputs */
+#ifdef COMPLEX
+ , const double Az [ ] /* size nz */
+ , double Rz [ ] /* size nz */
+ , Int do_conjugate /* if true, then do conjugate transpose */
+ /* otherwise, do array transpose */
+#endif
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, j, k, p, bp, nz, newj, ilast, do_values ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check inputs */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ ASSERT (n_col >= 0) ;
+ nz = Ap ? Ap [n_col] : 0 ;
+ DEBUG2 (("UMF_transpose: nz "ID"\n", nz)) ;
+ DEBUG2 (("n_row "ID" & "ID"\n", n_row, &n_row)) ;
+ DEBUG2 (("n_col "ID" & "ID"\n", n_col, &n_col)) ;
+ DEBUG2 (("Ap & "ID" to & "ID"\n", Ap, Ap + (n_col+1) - 1)) ;
+ DEBUG2 (("Ai & "ID" to & "ID"\n", Ai, Ai + (nz) - 1)) ;
+ if (Ax) DEBUG2 (("Ax & "ID" to & "ID"\n", Ax, Ax + (nz) - 1)) ;
+ if (P) DEBUG2 (("P & "ID" to & "ID"\n", P , P + (n_row) - 1)) ;
+ if (Q) DEBUG2 (("Q & "ID" to & "ID"\n", Q , Q + (n_col) - 1)) ;
+ DEBUG2 (("Rp & "ID" to & "ID"\n", Rp, Rp + (n_row+1) - 1)) ;
+ DEBUG2 (("Ri & "ID" to & "ID"\n", Ri, Ri + (nz) - 1)) ;
+ if (Rx) DEBUG2 (("Rx & "ID" to & "ID"\n", Rx, Rx + (nz) - 1)) ;
+ DEBUG2 (("W & "ID" to & "ID"\n", W, W + MAX(n_row,n_col) - 1)) ;
+#ifdef COMPLEX
+ if (Az) DEBUG2 (("Az & "ID" to & "ID"\n", Az, Az + (nz) - 1)) ;
+ if (Rz) DEBUG2 (("Rz & "ID" to & "ID"\n", Rz, Rz + (nz) - 1)) ;
+ DEBUG2 (("do_conjugate "ID" & "ID"\n", do_conjugate, &do_conjugate)) ;
+#endif
+#endif
+
+ if (check)
+ {
+ /* UMFPACK_symbolic skips this check */
+ /* UMFPACK_transpose always does this check */
+
+ if (!Ai || !Ap || !Ri || !Rp || !W)
+ {
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ if (n_row <= 0 || n_col <= 0) /* n_row,n_col must be > 0 */
+ {
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+
+ nz = Ap [n_col] ;
+ if (nz < 0) /* nz must be >= 0 */
+ {
+ return (UMFPACK_ERROR_nz_negative) ;
+ }
+
+ if (!UMF_is_permutation (P, W, n_row, n_row) ||
+ !UMF_is_permutation (Q, W, nq, nq))
+ {
+ return (UMFPACK_ERROR_invalid_permutation) ;
+ }
+
+ if (Ap [0] != 0)
+ {
+ return (UMFPACK_ERROR_Ap0_nonzero) ;
+ }
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ if (Ap [j] > Ap [j+1])
+ {
+ return (UMFPACK_ERROR_col_length_negative) ;
+ }
+ }
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ ilast = -1 ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+ if (i < 0 || i >= n_row)
+ {
+ return (UMFPACK_ERROR_row_index_out_of_bounds) ;
+ }
+ if (i <= ilast)
+ {
+ return (UMFPACK_ERROR_jumbled_matrix) ;
+ }
+ ilast = i ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ DEBUG2 (("UMF_transpose, input matrix:\n")) ;
+ UMF_dump_col_matrix (Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ Ai, Ap, n_row, n_col, nz) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* count the entries in each row of A */
+ /* ---------------------------------------------------------------------- */
+
+ /* use W as workspace for RowCount */
+
+ for (i = 0 ; i < n_row ; i++)
+ {
+ W [i] = 0 ;
+ Rp [i] = 0 ;
+ }
+
+ if (Q)
+ {
+ for (newj = 0 ; newj < nq ; newj++)
+ {
+ j = Q [newj] ;
+ ASSERT (j >= 0 && j < n_col) ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+ ASSERT (i >= 0 && i < n_row) ;
+ W [i]++ ;
+ }
+ }
+ }
+ else
+ {
+ for (j = 0 ; j < n_col ; j++)
+ {
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+ ASSERT (i >= 0 && i < n_row) ;
+ W [i]++ ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* compute the row pointers for R = A (P,Q) */
+ /* ---------------------------------------------------------------------- */
+
+ if (P)
+ {
+ Rp [0] = 0 ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ i = P [k] ;
+ ASSERT (i >= 0 && i < n_row) ;
+ Rp [k+1] = Rp [k] + W [i] ;
+ }
+ for (k = 0 ; k < n_row ; k++)
+ {
+ i = P [k] ;
+ ASSERT (i >= 0 && i < n_row) ;
+ W [i] = Rp [k] ;
+ }
+ }
+ else
+ {
+ Rp [0] = 0 ;
+ for (i = 0 ; i < n_row ; i++)
+ {
+ Rp [i+1] = Rp [i] + W [i] ;
+ }
+ for (i = 0 ; i < n_row ; i++)
+ {
+ W [i] = Rp [i] ;
+ }
+ }
+ ASSERT (Rp [n_row] <= Ap [n_col]) ;
+
+ /* at this point, W holds the permuted row pointers */
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the row form of B */
+ /* ---------------------------------------------------------------------- */
+
+ do_values = Ax && Rx ;
+#ifdef COMPLEX
+ do_values = do_values && Az && Rz ;
+#endif
+
+#ifdef COMPLEX
+ if (do_conjugate && do_values)
+ {
+ if (Q)
+ {
+
+ /* R = A (P,Q)' */
+ for (newj = 0 ; newj < nq ; newj++)
+ {
+ j = Q [newj] ;
+ ASSERT (j >= 0 && j < n_col) ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ bp = W [Ai [p]]++ ;
+ Ri [bp] = newj ;
+ Rx [bp] = Ax [p] ;
+ Rz [bp] = -Az [p] ;
+ }
+ }
+
+ }
+ else
+ {
+
+ /* R = A (P,:)' */
+ for (j = 0 ; j < n_col ; j++)
+ {
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ bp = W [Ai [p]]++ ;
+ Ri [bp] = j ;
+ Rx [bp] = Ax [p] ;
+ Rz [bp] = -Az [p] ;
+ }
+ }
+
+ }
+ }
+ else
+#endif
+ {
+ if (Q)
+ {
+ if (do_values)
+ {
+
+ /* R = A (P,Q).' */
+ for (newj = 0 ; newj < nq ; newj++)
+ {
+ j = Q [newj] ;
+ ASSERT (j >= 0 && j < n_col) ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ bp = W [Ai [p]]++ ;
+ Ri [bp] = newj ;
+ Rx [bp] = Ax [p] ;
+#ifdef COMPLEX
+ Rz [bp] = Az [p] ;
+#endif
+ }
+ }
+
+ }
+ else
+ {
+
+ /* R = pattern of A (P,Q).' */
+ for (newj = 0 ; newj < nq ; newj++)
+ {
+ j = Q [newj] ;
+ ASSERT (j >= 0 && j < n_col) ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ Ri [W [Ai [p]]++] = newj ;
+ }
+ }
+
+ }
+ }
+ else
+ {
+ if (do_values)
+ {
+
+ /* R = A (P,:).' */
+ for (j = 0 ; j < n_col ; j++)
+ {
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ bp = W [Ai [p]]++ ;
+ Ri [bp] = j ;
+ Rx [bp] = Ax [p] ;
+#ifdef COMPLEX
+ Rz [bp] = Az [p] ;
+#endif
+ }
+ }
+
+ }
+ else
+ {
+
+ /* R = pattern of A (P,:).' */
+ for (j = 0 ; j < n_col ; j++)
+ {
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ Ri [W [Ai [p]]++] = j ;
+ }
+ }
+
+ }
+ }
+
+ }
+
+#ifndef NDEBUG
+ for (k = 0 ; k < n_row ; k++)
+ {
+ if (P)
+ {
+ i = P [k] ;
+ }
+ else
+ {
+ i = k ;
+ }
+ DEBUG3 ((ID": W[i] "ID" Rp[k+1] "ID"\n", i, W [i], Rp [k+1])) ;
+ ASSERT (W [i] == Rp [k+1]) ;
+ }
+ DEBUG2 (("UMF_transpose, output matrix:\n")) ;
+ UMF_dump_col_matrix (Rx,
+#ifdef COMPLEX
+ Rz,
+#endif
+ Ri, Rp, n_col, n_row, Rp [n_row]) ;
+#endif
+
+ return (UMFPACK_OK) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_tuple_lengths.c b/src/sparse-matrix/umfpack/umf_tuple_lengths.c
new file mode 100644
index 0000000..12fea0f
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_tuple_lengths.c
@@ -0,0 +1,104 @@
+/* ========================================================================== */
+/* === UMF_tuple_lengths ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Determine the tuple list lengths, and the amount of memory required for */
+/* them. Return the amount of memory needed to store all the tuples. */
+/* This routine assumes that the tuple lists themselves are either already */
+/* deallocated, or will be shortly (so Row[ ].tlen and Col[ ].tlen are */
+/* overwritten) */
+
+#include "umf_internal.h"
+#include "umf_build_tuples_usage.h"
+
+GLOBAL Int UMF_tuple_lengths
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ double *dusage
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int e, nrows, ncols, nel, i, *Rows, *Cols, row, col, n_row, n_col, *E,
+ *Row_degree, *Row_tlen, *Col_degree, *Col_tlen, usage ;
+ Element *ep ;
+ Unit *p ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ E = Work->E ;
+ Row_degree = Numeric->Rperm ;
+ Col_degree = Numeric->Cperm ;
+ Row_tlen = Numeric->Uilen ;
+ Col_tlen = Numeric->Lilen ;
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ nel = Work->nel ;
+
+ DEBUG3 (("TUPLE_LENGTHS: n_row "ID" n_col "ID" nel "ID"\n",
+ n_row, n_col, nel)) ;
+
+ /* tuple list lengths already initialized to zero */
+
+ /* ---------------------------------------------------------------------- */
+ /* scan each element: count tuple list lengths (include element 0) */
+ /* ---------------------------------------------------------------------- */
+
+ for (e = 0 ; e <= nel ; e++) /* for all elements, in any order */
+ {
+ if (E [e])
+ {
+#ifndef NDEBUG
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+ p = Numeric->Memory + E [e] ;
+ GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncols) ;
+ nrows = ep->nrows ;
+ ASSERT (e != 0) ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ ASSERT (row == EMPTY || (row >= 0 && row < n_row)) ;
+ if (row >= 0)
+ {
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ Row_tlen [row] ++ ;
+ }
+ }
+ for (i = 0 ; i < ncols ; i++)
+ {
+ col = Cols [i] ;
+ ASSERT (col == EMPTY || (col >= 0 && col < n_col)) ;
+ if (col >= 0)
+ {
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ Col_tlen [col] ++ ;
+ }
+ }
+ }
+ }
+
+ /* note: tuple lengths are now modified, but the tuple lists are not */
+ /* updated to reflect that fact. */
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the required memory to hold all the tuple lists */
+ /* ---------------------------------------------------------------------- */
+
+ usage = UMF_build_tuples_usage (Col_tlen, Col_degree,
+ Row_tlen, Row_degree, n_row, n_col, dusage) ;
+ return (usage) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_usolve.c b/src/sparse-matrix/umfpack/umf_usolve.c
new file mode 100644
index 0000000..4347eb4
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_usolve.c
@@ -0,0 +1,167 @@
+/* ========================================================================== */
+/* === UMF_usolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* solves Ux = 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 UMF_usolve
+(
+ NumericType *Numeric,
+ Entry X [ ], /* b on input, solution x on output */
+ Int Pattern [ ] /* a work array of size n */
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int k, deg, j, *ip, col, *Upos, *Uilen, pos,
+ *Uip, n, ulen, up, newUchain, npiv ;
+ Entry *xp, xk, *D ;
+ double flops ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+
+ /* start by counting the division by D [0..n-1] */
+ flops = n ;
+
+#ifndef NDEBUG
+ DEBUG4 (("Usolve start: npiv = "ID" n = "ID"\n", npiv, n)) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ DEBUG4 (("Usolve start "ID": ", j)) ;
+ EDEBUG4 (X [j]) ;
+ DEBUG4 (("\n")) ;
+ }
+#endif
+
+ /* handle the singular part of D, up to just before the last pivot */
+ flops += (n-npiv) ;
+ for (k = n-1 ; k >= npiv ; k--)
+ {
+ /* Note that D [k] is identically zero. */
+ ASSERT (IS_ZERO (D [k])) ;
+ xk = X [k] ;
+ /* X [k] = xk / D [k] ; */
+ DIV (X [k], xk, D [k]) ;
+ }
+
+ deg = Numeric->ulen ;
+ if (deg > 0)
+ {
+ /* make last pivot row of U (singular matrices only) */
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG1 (("Last row of U: j="ID"\n", j)) ;
+ DEBUG1 (("Last row of U: Upattern[j]="ID"\n",
+ Numeric->Upattern [j]) );
+ Pattern [j] = Numeric->Upattern [j] ;
+ }
+ }
+
+ for (k = npiv-1 ; k >= 0 ; k--)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* use row k of U */
+ /* ------------------------------------------------------------------ */
+
+ up = Uip [k] ;
+ ulen = Uilen [k] ;
+ newUchain = (up < 0) ;
+ if (newUchain)
+ {
+ up = -up ;
+ xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+ }
+ else
+ {
+ xp = (Entry *) (Numeric->Memory + up) ;
+ }
+
+ xk = X [k] ;
+ flops += 2*deg ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" k "ID" col "ID" value", k, Pattern [j])) ;
+ EDEBUG4 (*xp) ;
+ DEBUG4 (("\n")) ;
+ /* xk -= X [Pattern [j]] * (*xp) ; */
+ MULT_SUB (xk, X [Pattern [j]], *xp) ;
+ xp++ ;
+ }
+
+ /* Go ahead and divide by zero if D [k] is zero */
+ /* X [k] = xk / D [k] ; */
+ DIV (X [k], xk, D [k]) ;
+
+ /* ------------------------------------------------------------------ */
+ /* make row k-1 of U in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ if (newUchain)
+ {
+ /* next row is a new Uchain */
+ deg = ulen ;
+ ASSERT (IMPLIES (k == 0, deg == 0)) ;
+ 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 ;
+ }
+ }
+ else
+ {
+ deg -= ulen ;
+ 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 pos "ID"\n", k, pos)) ;
+ ASSERT (pos >= 0 && pos <= deg) ;
+ Pattern [deg++] = Pattern [pos] ;
+ Pattern [pos] = k ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ for (j = 0 ; j < n ; j++)
+ {
+ DEBUG4 (("Usolve done "ID": ", j)) ;
+ EDEBUG4 (X [j]) ;
+ DEBUG4 (("\n")) ;
+ }
+ DEBUG4 (("Usolve done.\n")) ;
+#endif
+
+ return (DIV_FLOPS * ((double) n) + MULTSUB_FLOPS * ((double) Numeric->unz));
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_utsolve.c b/src/sparse-matrix/umfpack/umf_utsolve.c
new file mode 100644
index 0000000..19eeb64
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_utsolve.c
@@ -0,0 +1,255 @@
+/* ========================================================================== */
+/* === UMF_utsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* 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_SOLVE
+UMF_uhsolve /* solve U'x=b (complex conjugate transpose) */
+#else
+UMF_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 */
+ /* ---------------------------------------------------------------------- */
+
+ Int k, deg, j, *ip, col, *Upos, *Uilen, kstart, kend, up,
+ *Uip, n, uhead, ulen, pos, npiv ;
+ Entry *xp, xk, *D ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+
+#ifndef NDEBUG
+ DEBUG4 (("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
+
+ for (kstart = 0 ; 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 */
+ /* -------------------------------------------------------------- */
+
+ /* 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
+ X [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) ;
+#endif
+ xp++ ;
+ }
+ }
+ }
+ ASSERT (uhead == n) ;
+ }
+
+ for (k = npiv ; k < n ; k++)
+ {
+ /* Note that D [k] is identically zero. */
+ 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 ;
+ }
+
+#ifndef NDEBUG
+ for (j = 0 ; j < n ; j++)
+ {
+ DEBUG4 (("Utsolve done "ID": ", j)) ;
+ EDEBUG4 (X [j]) ;
+ DEBUG4 (("\n")) ;
+ }
+ DEBUG4 (("Utsolve done.\n")) ;
+#endif
+
+ return (DIV_FLOPS * ((double) n) + MULTSUB_FLOPS * ((double) Numeric->unz));
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_valid_numeric.c b/src/sparse-matrix/umfpack/umf_valid_numeric.c
new file mode 100644
index 0000000..b1fd91d
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_valid_numeric.c
@@ -0,0 +1,48 @@
+/* ========================================================================== */
+/* === UMF_valid_numeric ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* Returns TRUE if the Numeric object is valid, FALSE otherwise. */
+/* Does not check everything. UMFPACK_report_numeric checks more. */
+
+#include "umf_internal.h"
+
+GLOBAL Int UMF_valid_numeric
+(
+ NumericType *Numeric
+)
+{
+ /* This routine does not check the contents of the individual arrays, so */
+ /* it can miss some errors. All it checks for is the presence of the */
+ /* arrays, and the Numeric "valid" entry. */
+
+ if (!Numeric)
+ {
+ return (FALSE) ;
+ }
+
+ if (Numeric->valid != NUMERIC_VALID)
+ {
+ /* Numeric does not point to a NumericType object */
+ return (FALSE) ;
+ }
+
+ if (Numeric->n_row <= 0 || Numeric->n_col <= 0 || !Numeric->D ||
+ !Numeric->Rperm || !Numeric->Cperm ||
+ !Numeric->Lpos || !Numeric->Upos ||
+ !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip || !Numeric->Uip ||
+ !Numeric->Memory || (Numeric->ulen > 0 && !Numeric->Upattern))
+ {
+ return (FALSE) ;
+ }
+
+ return (TRUE) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umf_valid_symbolic.c b/src/sparse-matrix/umfpack/umf_valid_symbolic.c
new file mode 100644
index 0000000..b7ddc35
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umf_valid_symbolic.c
@@ -0,0 +1,49 @@
+/* ========================================================================== */
+/* === UMF_valid_symbolic =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_internal.h"
+
+/* Returns TRUE if the Symbolic object is valid, FALSE otherwise. */
+/* The UMFPACK_report_symbolic routine does a more thorough check. */
+
+GLOBAL Int UMF_valid_symbolic
+(
+ SymbolicType *Symbolic
+)
+{
+ /* This routine does not check the contents of the individual arrays, so */
+ /* it can miss some errors. All it checks for is the presence of the */
+ /* arrays, and the Symbolic "valid" entry. */
+
+ if (!Symbolic)
+ {
+ return (FALSE) ;
+ }
+
+ if (Symbolic->valid != SYMBOLIC_VALID)
+ {
+ /* Symbolic does not point to a SymbolicType object */
+ return (FALSE) ;
+ }
+
+ if (!Symbolic->Cperm_init || !Symbolic->Rperm_init ||
+ !Symbolic->Front_npivcol || !Symbolic->Front_1strow ||
+ !Symbolic->Front_leftmostdesc ||
+ !Symbolic->Front_parent || !Symbolic->Chain_start ||
+ !Symbolic->Chain_maxrows || !Symbolic->Chain_maxcols ||
+ Symbolic->n_row <= 0 || Symbolic->n_col <= 0)
+ {
+ return (FALSE) ;
+ }
+
+ return (TRUE) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_defaults.c b/src/sparse-matrix/umfpack/umfpack_defaults.c
new file mode 100644
index 0000000..57d8433
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_defaults.c
@@ -0,0 +1,111 @@
+/* ========================================================================== */
+/* === UMFPACK_defaults ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Sets default control parameters. See umfpack_defaults.h
+ for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_defaults
+(
+ double Control [UMFPACK_CONTROL]
+)
+{
+ Int i ;
+
+ if (!Control)
+ {
+ /* silently return if no Control array */
+ return ;
+ }
+
+ for (i = 0 ; i < UMFPACK_CONTROL ; i++)
+ {
+ Control [i] = 0 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* default control settings: can be modified at run-time */
+ /* ---------------------------------------------------------------------- */
+
+ /* used in UMFPACK_report_* routines: */
+ Control [UMFPACK_PRL] = UMFPACK_DEFAULT_PRL ;
+
+ /* used in UMFPACK_*symbolic: */
+ Control [UMFPACK_DENSE_ROW] = UMFPACK_DEFAULT_DENSE_ROW ;
+ Control [UMFPACK_DENSE_COL] = UMFPACK_DEFAULT_DENSE_COL ;
+
+ /* used in UMFPACK_numeric: */
+ Control [UMFPACK_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_PIVOT_TOLERANCE ;
+ Control [UMFPACK_BLOCK_SIZE] = UMFPACK_DEFAULT_BLOCK_SIZE ;
+ Control [UMFPACK_RELAXED_AMALGAMATION] =
+ UMFPACK_DEFAULT_RELAXED_AMALGAMATION ;
+ Control [UMFPACK_RELAXED2_AMALGAMATION] =
+ UMFPACK_DEFAULT_RELAXED2_AMALGAMATION ;
+ Control [UMFPACK_RELAXED3_AMALGAMATION] =
+ UMFPACK_DEFAULT_RELAXED3_AMALGAMATION ;
+ Control [UMFPACK_ALLOC_INIT] = UMFPACK_DEFAULT_ALLOC_INIT ;
+
+ /* used in UMFPACK_*solve: */
+ Control [UMFPACK_IRSTEP] = UMFPACK_DEFAULT_IRSTEP ;
+
+ /* ---------------------------------------------------------------------- */
+ /* compile-time settings: cannot be modified at run-time */
+ /* ---------------------------------------------------------------------- */
+
+#ifdef USE_NO_BLAS
+ /* use externally-provided BLAS (dgemm, dger, dgemv, zgemm, zgeru, zgemv) */
+ Control [UMFPACK_COMPILED_WITH_BLAS] = 1 ;
+#else
+ /* do not use the BLAS - use in-line C code instead */
+ Control [UMFPACK_COMPILED_WITH_BLAS] = 0 ;
+#endif
+
+#ifdef MATLAB_MEX_FILE
+ /* use mxMalloc, mxFree, mxRealloc, and mexPrintf */
+ /* use mxAssert if debugging is enabled */
+ Control [UMFPACK_COMPILED_FOR_MATLAB] = 1 ;
+#else
+#ifdef MATHWORKS
+ /* use internal utMalloc, utFree, utRealloc, and utPrintf routines. */
+ /* use utDivideComplex and utFdlibm_hypot for complex version. */
+ /* use utAssert if debugging is enabled. */
+ Control [UMFPACK_COMPILED_FOR_MATLAB] = 2 ;
+#else
+ /* use ANSI C malloc, free, realloc, and print */
+ /* use ANSI C assert if debugging is enabled */
+ Control [UMFPACK_COMPILED_FOR_MATLAB] = 0 ;
+#endif
+#endif
+
+#ifdef GETRUSAGE
+ /* uses the non-standard getrusage to get CPU time (Solaris) */
+ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 1 ;
+#else
+ /* uses the ANSI standard clock routine to get CPU time */
+ /* this may wrap around */
+ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 0 ;
+#endif
+
+#ifndef NDEBUG
+ /* UMFPACK is compiled in debug mode. */
+ /* This is exceedingly slow. */
+ PRINTF (("UMFPACK is running in debug mode. This is very slow!\n")) ;
+ Control [UMFPACK_COMPILED_IN_DEBUG_MODE] = 1 ;
+#else
+ /* UMFPACK is compiled in normal (non-debug) mode */
+ Control [UMFPACK_COMPILED_IN_DEBUG_MODE] = 0 ;
+#endif
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_free_numeric.c b/src/sparse-matrix/umfpack/umfpack_free_numeric.c
new file mode 100644
index 0000000..2e7d339
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_free_numeric.c
@@ -0,0 +1,51 @@
+/* ========================================================================== */
+/* === UMFPACK_free_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/* User-callable. Free the entire Numeric object.
+ See UMFPACK_free_numeric.h for details.
+*/
+
+#include "umf_internal.h"
+#include "umf_free.h"
+
+GLOBAL void UMFPACK_free_numeric
+(
+ void **NumericHandle
+)
+{
+
+ NumericType *Numeric ;
+ if (!NumericHandle)
+ {
+ return ;
+ }
+ Numeric = *((NumericType **) NumericHandle) ;
+ if (!Numeric)
+ {
+ return ;
+ }
+
+ (void) UMF_free ((void *) Numeric->D) ;
+ (void) UMF_free ((void *) Numeric->Rperm) ;
+ (void) UMF_free ((void *) Numeric->Cperm) ;
+ (void) UMF_free ((void *) Numeric->Lpos) ;
+ (void) UMF_free ((void *) Numeric->Lilen) ;
+ (void) UMF_free ((void *) Numeric->Lip) ;
+ (void) UMF_free ((void *) Numeric->Upos) ;
+ (void) UMF_free ((void *) Numeric->Uilen) ;
+ (void) UMF_free ((void *) Numeric->Uip) ;
+ (void) UMF_free ((void *) Numeric->Upattern) ;
+ (void) UMF_free ((void *) Numeric->Memory) ;
+ (void) UMF_free ((void *) Numeric) ;
+
+ *NumericHandle = (void *) NULL ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_free_symbolic.c b/src/sparse-matrix/umfpack/umfpack_free_symbolic.c
new file mode 100644
index 0000000..a2389ee
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_free_symbolic.c
@@ -0,0 +1,50 @@
+/* ========================================================================== */
+/* === UMFPACK_free_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. See umfpack_free_symbolic.h for details.
+ All 10 objects comprising the Symbolic object are free'd via UMF_free.
+*/
+
+#include "umf_internal.h"
+#include "umf_free.h"
+
+GLOBAL void UMFPACK_free_symbolic
+(
+ void **SymbolicHandle
+)
+{
+
+ SymbolicType *Symbolic ;
+ if (!SymbolicHandle)
+ {
+ return ;
+ }
+ Symbolic = *((SymbolicType **) SymbolicHandle) ;
+ if (!Symbolic)
+ {
+ return ;
+ }
+
+ (void) UMF_free ((void *) Symbolic->Cperm_init) ;
+ (void) UMF_free ((void *) Symbolic->Rperm_init) ;
+ (void) UMF_free ((void *) Symbolic->Front_npivcol) ;
+ (void) UMF_free ((void *) Symbolic->Front_parent) ;
+ (void) UMF_free ((void *) Symbolic->Front_1strow) ;
+ (void) UMF_free ((void *) Symbolic->Front_leftmostdesc) ;
+ (void) UMF_free ((void *) Symbolic->Chain_start) ;
+ (void) UMF_free ((void *) Symbolic->Chain_maxrows) ;
+ (void) UMF_free ((void *) Symbolic->Chain_maxcols) ;
+ (void) UMF_free ((void *) Symbolic) ;
+
+ *SymbolicHandle = (void *) NULL ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_get_lunz.c b/src/sparse-matrix/umfpack/umfpack_get_lunz.c
new file mode 100644
index 0000000..b7b7ec3
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_get_lunz.c
@@ -0,0 +1,57 @@
+/* ========================================================================== */
+/* === UMFPACK_get_lunz ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Determines the number of nonzeros in L and U, and the size
+ of L and U.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+GLOBAL Int UMFPACK_get_lunz
+(
+ Int *lnz,
+ Int *unz,
+ Int *n_row,
+ Int *n_col,
+ Int *nz_udiag,
+ void *NumericHandle
+)
+{
+ NumericType *Numeric ;
+
+ Numeric = (NumericType *) NumericHandle ;
+
+ if (!UMF_valid_numeric (Numeric))
+ {
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+ if (!lnz || !unz || !n_row || !n_col || !nz_udiag)
+ {
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ *n_row = Numeric->n_row ;
+ *n_col = Numeric->n_col ;
+
+ /* number of nz's in L below diagonal, plus the unit diagonal of L */
+ *lnz = Numeric->lnz + MIN (Numeric->n_row, Numeric->n_col) ;
+
+ /* number of nz's in U above diagonal, plus nz's on diagaonal of U */
+ *unz = Numeric->unz + Numeric->nnzpiv ;
+
+ /* number of nz's on the diagonal */
+ *nz_udiag = Numeric->nnzpiv ;
+
+ return (UMFPACK_OK) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_get_numeric.c b/src/sparse-matrix/umfpack/umfpack_get_numeric.c
new file mode 100644
index 0000000..55b9b87
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_get_numeric.c
@@ -0,0 +1,816 @@
+/* ========================================================================== */
+/* === UMFPACK_get_numeric ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Gets the LU factors and the permutation vectors held in the
+ Numeric object. L is returned in sparse row form with sorted rows, U is
+ returned in sparse column form with sorted columns, and P and Q are
+ returned as permutation vectors. See umfpack_get_numeric.h for a more
+ detailed description.
+
+ Returns TRUE if successful, FALSE if the Numeric object is invalid or
+ if out of memory.
+
+ Dynamic memory usage: calls UMF_malloc twice, for a total space of
+ 2*n integers, and then frees all of it via UMF_free when done.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+PRIVATE void get_L
+(
+ Int Lp [ ],
+ Int Lj [ ],
+ double Lx [ ],
+#ifdef COMPLEX
+ double Lz [ ],
+#endif
+ NumericType *Numeric,
+ Int Pattern [ ],
+ Int Wi [ ]
+) ;
+
+PRIVATE void get_U
+(
+ Int Up [ ],
+ Int Ui [ ],
+ double Ux [ ],
+#ifdef COMPLEX
+ double Uz [ ],
+#endif
+ NumericType *Numeric,
+ Int Pattern [ ],
+ Int Wi [ ]
+) ;
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_get_numeric
+(
+ Int Lp [ ],
+ Int Lj [ ],
+ double Lx [ ],
+#ifdef COMPLEX
+ double Lz [ ],
+#endif
+ Int Up [ ],
+ Int Ui [ ],
+ double Ux [ ],
+#ifdef COMPLEX
+ double Uz [ ],
+#endif
+ Int P [ ],
+ Int Q [ ],
+ double Dx [ ],
+#ifdef COMPLEX
+ double Dz [ ],
+#endif
+ void *NumericHandle
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ NumericType *Numeric ;
+ Int getL, getU, *Rperm, *Cperm, k, nn, n_row, n_col, *Wi, *Pattern,
+ n_inner ;
+
+#ifndef NDEBUG
+ init_count = UMF_malloc_count ;
+#endif
+
+ Wi = (Int *) NULL ;
+ Pattern = (Int *) NULL ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check input parameters */
+ /* ---------------------------------------------------------------------- */
+
+ Numeric = (NumericType *) NumericHandle ;
+ if (!UMF_valid_numeric (Numeric))
+ {
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ n_row = Numeric->n_row ;
+ n_col = Numeric->n_col ;
+ nn = MAX (n_row, n_col) ;
+ n_inner = MIN (n_row, n_col) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate workspace */
+ /* ---------------------------------------------------------------------- */
+
+#ifdef COMPLEX
+ getL = Lp && Lj && Lx && Lz ;
+ getU = Up && Ui && Ux && Uz ;
+#else
+ getL = Lp && Lj && Lx ;
+ getU = Up && Ui && Ux ;
+#endif
+
+ if (getL || getU)
+ {
+ Wi = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ Pattern = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ if (!Wi || !Pattern)
+ {
+ (void) UMF_free ((void *) Wi) ;
+ (void) UMF_free ((void *) Pattern) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ ASSERT (UMF_malloc_count == init_count + 2) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* get contents of Numeric */
+ /* ---------------------------------------------------------------------- */
+
+ if (P)
+ {
+ Rperm = Numeric->Rperm ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ P [k] = Rperm [k] ;
+ }
+ }
+
+ if (Q)
+ {
+ Cperm = Numeric->Cperm ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Q [k] = Cperm [k] ;
+ }
+ }
+
+ if (getL)
+ {
+ get_L (Lp, Lj, Lx,
+#ifdef COMPLEX
+ Lz,
+#endif
+ Numeric, Pattern, Wi) ;
+ }
+
+ if (getU)
+ {
+ get_U (Up, Ui, Ux,
+#ifdef COMPLEX
+ Uz,
+#endif
+ Numeric, Pattern, Wi) ;
+ }
+
+ if (Dx)
+ {
+ for (k = 0 ; k < n_inner ; k++)
+ {
+ Dx [k] = REAL_COMPONENT (Numeric->D [k]) ;
+ }
+ }
+
+#ifdef COMPLEX
+ if (Dz)
+ {
+ for (k = 0 ; k < n_inner ; k++)
+ {
+ Dz [k] = IMAG_COMPONENT (Numeric->D [k]) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* free the workspace */
+ /* ---------------------------------------------------------------------- */
+
+ (void) UMF_free ((void *) Wi) ;
+ (void) UMF_free ((void *) Pattern) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+
+ return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === get_L ================================================================ */
+/* ========================================================================== */
+
+/*
+ The matrix L is stored in the following arrays in the Numeric object:
+
+ Int Lpos [0..npiv]
+ Int Lip [0..npiv], index into Numeric->Memory
+ Int Lilen [0..npiv]
+ Unit *(Numeric->Memory), pointer to memory space holding row indices
+ and numerical values
+
+ where npiv is the number of pivot entries found. If A is n_row-by-n_col,
+ then npiv <= MIN (n_row,n_col).
+
+ Let L_k denote the pattern of entries in column k of L (excluding the
+ diagonal).
+
+ An Lchain is a sequence of columns of L whose nonzero patterns are related.
+ The start of an Lchain is denoted by a negative value of Lip [k].
+
+ To obtain L_k:
+
+ (1) If column k starts an Lchain, then L_k is stored in its entirety.
+ |Lip [k]| is an index into Numeric->Memory for the integer row indices
+ in L_k. The number of entries in the column is |L_k| = Lilen [k].
+ This defines the pattern of the "leading" column of this chain.
+ Lpos [k] is not used for the first column in the chain. Column zero
+ is always a leading column.
+
+ (2) If column k does not start an Lchain, then L_k is represented as a
+ superset of L_k-1. Define Lnew_k such that (L_k-1 - {k} union Lnew_k)
+ = L_k, where Lnew_k and (L_k-1)-{k} are disjoint. Lnew_k are the
+ entries in L_k that are not in L_k-1. Lpos [k] holds the position of
+ pivot row index k in the prior pattern L_k-1 (if it is present), so
+ that the set subtraction (L_k-1)-{k} can be computed quickly, when
+ computing the pattern of L_k from L_k-1. The number of new entries in
+ L_k is stored in Lilen [k] = |Lnew_k|.
+
+ Note that this means we must have the pattern L_k-1 to compute L_k.
+
+ In both cases (1) and (2), we obtain the pattern L_k.
+
+ The numerical values are stored in Numeric->Memory, starting at the index
+ |Lip [k]| + Lilen [k]. It is stored in the same order as the entries
+ in L_k, after L_k is obtained from cases (1) or (2), above.
+
+ The advantage of using this "packed" data structure is that it can
+ dramatically reduce the amount of storage needed for the pattern of L.
+ The disadvantage is that it can be difficult for the user to access,
+ and it does not match the sparse matrix data structure used in MATLAB.
+ Thus, this routine is provided to create a conventional sparse matrix
+ data structure for L, in sparse-row form. A row-form of L appears to
+ MATLAB to be a column-oriented from of the transpose of L. If you would
+ like a column-form of L, then use UMFPACK_transpose (an example of this
+ is in umfpackmex.c).
+
+*/
+/* ========================================================================== */
+
+PRIVATE void get_L
+(
+ Int Lp [ ], /* of size n_row+1 */
+ Int Lj [ ], /* of size lnz, where lnz = Lp [n_row] */
+ double Lx [ ], /* of size lnz */
+#ifdef COMPLEX
+ double Lz [ ], /* of size lnz */
+#endif
+ NumericType *Numeric,
+ Int Pattern [ ], /* workspace of size n_row */
+ Int Wi [ ] /* workspace of size n_row */
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int deg, *ip, j, row, n_row, n_col, n_inner, *Lpos, *Lilen, *Lip, p, llen,
+ lnz2, lp, newLchain, k, pos, npiv ;
+ Entry *xp, value ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG4 (("get_L start:\n")) ;
+ n_row = Numeric->n_row ;
+ n_col = Numeric->n_col ;
+ n_inner = MIN (n_row, n_col) ;
+ npiv = Numeric->npiv ;
+ Lpos = Numeric->Lpos ;
+ Lilen = Numeric->Lilen ;
+ Lip = Numeric->Lip ;
+ deg = 0 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* count the nonzeros in each row of L */
+ /* ---------------------------------------------------------------------- */
+
+ for (row = 0 ; row < n_inner ; row++)
+ {
+ /* include the diagonal entry in the row counts */
+ Wi [row] = 1 ;
+ }
+ for (row = n_inner ; row < n_row ; row++)
+ {
+ Wi [row] = 0 ;
+ }
+
+ /* count the nonzero entries in L */
+ for (k = 0 ; k < npiv ; k++)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* make column of L in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ lp = Lip [k] ;
+ newLchain = (lp < 0) ;
+ if (newLchain)
+ {
+ lp = -lp ;
+ deg = 0 ;
+ DEBUG4 (("start of chain for column of L\n")) ;
+ }
+
+ /* remove pivot row */
+ pos = Lpos [k] ;
+ if (pos != EMPTY)
+ {
+ DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n",
+ k, Pattern [pos], pos)) ;
+ ASSERT (!newLchain) ;
+ ASSERT (deg > 0) ;
+ ASSERT (pos >= 0 && pos < deg) ;
+ ASSERT (Pattern [pos] == k) ;
+ Pattern [pos] = Pattern [--deg] ;
+ }
+
+ /* concatenate the pattern */
+ ip = (Int *) (Numeric->Memory + lp) ;
+ llen = Lilen [k] ;
+ for (j = 0 ; j < llen ; j++)
+ {
+ row = *ip++ ;
+ DEBUG4 ((" row "ID" k "ID"\n", row, k)) ;
+ ASSERT (row > k && row < n_row) ;
+ Pattern [deg++] = row ;
+ }
+
+ xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ;
+ row = Pattern [j] ;
+ value = *xp++ ;
+ EDEBUG4 (value) ;
+ DEBUG4 (("\n")) ;
+ if (IS_NONZERO (value))
+ {
+ Wi [row]++ ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the final row form of L */
+ /* ---------------------------------------------------------------------- */
+
+ /* create the row pointers */
+ lnz2 = 0 ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Lp [row] = lnz2 ;
+ lnz2 += Wi [row] ;
+ Wi [row] = Lp [row] ;
+ }
+ Lp [n_row] = lnz2 ;
+ ASSERT (Numeric->lnz + n_inner == lnz2) ;
+
+ /* add entries from the rows of L */
+ for (k = 0 ; k < npiv ; k++)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* make column of L in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ lp = Lip [k] ;
+ newLchain = (lp < 0) ;
+ if (newLchain)
+ {
+ lp = -lp ;
+ deg = 0 ;
+ DEBUG4 (("start of chain for column of L\n")) ;
+ }
+
+ /* remove pivot row */
+ pos = Lpos [k] ;
+ if (pos != EMPTY)
+ {
+ DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n",
+ k, Pattern [pos], pos)) ;
+ ASSERT (!newLchain) ;
+ ASSERT (deg > 0) ;
+ ASSERT (pos >= 0 && pos < deg) ;
+ ASSERT (Pattern [pos] == k) ;
+ Pattern [pos] = Pattern [--deg] ;
+ }
+
+ /* concatenate the pattern */
+ ip = (Int *) (Numeric->Memory + lp) ;
+ llen = Lilen [k] ;
+ for (j = 0 ; j < llen ; j++)
+ {
+ row = *ip++ ;
+ DEBUG4 ((" row "ID" k "ID"\n", row, k)) ;
+ ASSERT (row > k) ;
+ Pattern [deg++] = row ;
+ }
+
+ xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ;
+
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ;
+ row = Pattern [j] ;
+ value = *xp++ ;
+ EDEBUG4 (value) ;
+ DEBUG4 (("\n")) ;
+ if (IS_NONZERO (value))
+ {
+ p = Wi [row]++ ;
+ Lj [p] = k ;
+ Lx [p] = REAL_COMPONENT (value) ;
+#ifdef COMPLEX
+ Lz [p] = IMAG_COMPONENT (value) ;
+#endif
+ }
+ }
+ }
+
+ /* add all of the diagonal entries (L is unit diagonal) */
+ for (row = 0 ; row < n_inner ; row++)
+ {
+ p = Wi [row]++ ;
+ Lj [p] = row ;
+ Lx [p] = 1. ;
+#ifdef COMPLEX
+ Lz [p] = 0. ;
+#endif
+ ASSERT (Wi [row] == Lp [row+1]) ;
+ }
+
+#ifndef NDEBUG
+ DEBUG6 (("L matrix (stored by rows):")) ;
+ UMF_dump_col_matrix (Lx,
+#ifdef COMPLEX
+ Lz,
+#endif
+ Lj, Lp, n_inner, n_row, Numeric->lnz+n_inner) ;
+#endif
+
+ DEBUG4 (("get_L done:\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === get_U ================================================================ */
+/* ========================================================================== */
+
+/*
+ The matrix U is stored in the following arrays in the Numeric object:
+
+ Int Upos [0..npiv]
+ Int Uip [0..npiv], index into Numeric->Memory
+ Int Uilen [0..npiv]
+ Unit *(Numeric->Memory), pointer to memory space holding column indices
+ and numerical values
+
+ where npiv is the number of pivot entries found. If A is n_row-by-n_col,
+ then npiv <= MIN (n_row,n_col).
+
+ Let U_k denote the pattern of entries in row k of U (excluding the
+ diagonal).
+
+ A Uchain is a sequence of columns of U whose nonzero patterns are related.
+ The start of a Uchain is denoted by a negative value of Uip [k].
+
+ To obtain U_k-1:
+
+ (1) If row k is the start of a Uchain then Uip [k] is negative and |Uip [k]|
+ is an index into Numeric->Memory for the integer column indices in
+ U_k-1. The number of entries in the row is |U_k-1| = Uilen [k]. This
+ defines the pattern of the "trailing" row of this chain that ends at
+ row k-1.
+
+
+ (2) If row k is not the start of a Uchain, then U_k-1 is a subset of U_k.
+ The indices in U_k are arranged so that last Uilen [k] entries of
+ U_k are those indices not in U_k-1. Next, the pivot column index k is
+ added if it appears in row U_k-1 (it never appears in U_k). Upos [k]
+ holds the position of pivot column index k in the pattern U_k-1 (if it
+ is present), so that the set union (U_k-1)+{k} can be computed quickly,
+ when computing the pattern of U_k-1 from U_k.
+
+ Note that this means we must have the pattern U_k to compute L_k-1.
+
+ In both cases (1) and (2), we obtain the pattern U_k.
+
+ The numerical values are stored in Numeric->Memory. If k is the start of a
+ Uchain, then the offset is |Uip [k]| plus the size of the space needed to
+ store the pattern U_k-1. Otherwise, Uip [k] is the offset itself of the
+ numerical values, since in this case no pattern is stored.
+ The numerical values are stored in the same order as the entries in U_k,
+ after U_k is obtained from cases (1) or (2), above.
+
+ The advantage of using this "packed" data structure is that it can
+ dramatically reduce the amount of storage needed for the pattern of U.
+ The disadvantage is that it can be difficult for the user to access,
+ and it does not match the sparse matrix data structure used in MATLAB.
+ Thus, this routine is provided to create a conventional sparse matrix
+ data structure for U, in sparse-column form.
+
+*/
+/* ========================================================================== */
+
+PRIVATE void get_U
+(
+ Int Up [ ], /* of size n_col+1 */
+ Int Ui [ ], /* of size unz, where unz = Up [n_col] */
+ double Ux [ ], /* of size unz */
+#ifdef COMPLEX
+ double Uz [ ], /* of size unz */
+#endif
+ NumericType *Numeric,
+ Int Pattern [ ], /* workspace of size n_col */
+ Int Wi [ ] /* workspace of size n_col */
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int deg, j, *ip, col, *Upos, *Uilen, *Uip, n_col, ulen,
+ unz2, p, k, up, newUchain, pos, npiv ;
+ Entry *xp, *D, value ;
+
+#ifndef NDEBUG
+ Int nnzpiv = 0 ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG4 (("get_U start:\n")) ;
+ n_col = Numeric->n_col ;
+ npiv = Numeric->npiv ;
+ Upos = Numeric->Upos ;
+ Uilen = Numeric->Uilen ;
+ Uip = Numeric->Uip ;
+ D = Numeric->D ;
+
+ /* ---------------------------------------------------------------------- */
+ /* count the nonzeros in each column of U */
+ /* ---------------------------------------------------------------------- */
+
+ for (col = 0 ; col < npiv ; col++)
+ {
+ /* include the diagonal entry in the column counts */
+ DEBUG4 (("D ["ID"] = ", col)) ;
+ EDEBUG4 (D [col]) ;
+ Wi [col] = IS_NONZERO (D [col]) ;
+ DEBUG4 ((" is nonzero: "ID"\n", Wi [col])) ;
+#ifndef NDEBUG
+ nnzpiv += IS_NONZERO (D [col]) ;
+#endif
+ }
+ DEBUG4 (("nnzpiv "ID" "ID"\n", nnzpiv, Numeric->nnzpiv)) ;
+ ASSERT (nnzpiv == Numeric->nnzpiv) ;
+ for (col = npiv ; col < n_col ; col++)
+ {
+ /* diagonal entries are zero for structurally singular part */
+ Wi [col] = 0 ;
+ }
+
+ deg = Numeric->ulen ;
+ if (deg > 0)
+ {
+ /* make last pivot row of U (singular matrices only) */
+ DEBUG0 (("Last pivot row of U: ulen "ID"\n", deg)) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ Pattern [j] = Numeric->Upattern [j] ;
+ DEBUG0 ((" column "ID"\n", Pattern [j])) ;
+ }
+ }
+
+ for (k = npiv-1 ; k >= 0 ; k--)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* use row k of U */
+ /* ------------------------------------------------------------------ */
+
+ up = Uip [k] ;
+ ulen = Uilen [k] ;
+ newUchain = (up < 0) ;
+ if (newUchain)
+ {
+ 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\n", k, Pattern [j])) ;
+ col = Pattern [j] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ value = *xp++ ;
+ EDEBUG4 (value) ;
+ DEBUG4 (("\n")) ;
+ if (IS_NONZERO (value))
+ {
+ Wi [col]++ ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* make row k-1 of U in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ if (newUchain)
+ {
+ /* next row is a new Uchain */
+ deg = ulen ;
+ 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 ;
+ }
+ }
+ else
+ {
+ deg -= ulen ;
+ DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, 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 ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the final column form of U */
+ /* ---------------------------------------------------------------------- */
+
+ /* create the column pointers */
+ unz2 = 0 ;
+ for (col = 0 ; col < n_col ; col++)
+ {
+ Up [col] = unz2 ;
+ unz2 += Wi [col] ;
+ }
+ Up [n_col] = unz2 ;
+ DEBUG1 (("Numeric->unz "ID" npiv "ID" nnzpiv "ID" unz2 "ID"\n",
+ Numeric->unz, npiv, Numeric->nnzpiv, unz2)) ;
+ ASSERT (Numeric->unz + Numeric->nnzpiv == unz2) ;
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ Wi [col] = Up [col+1] ;
+ }
+
+ /* add all of the diagonal entries */
+ for (col = 0 ; col < npiv ; col++)
+ {
+ if (IS_NONZERO (D [col]))
+ {
+ p = --(Wi [col]) ;
+ Ui [p] = col ;
+ Ux [p] = REAL_COMPONENT (D [col]) ;
+#ifdef COMPLEX
+ Uz [p] = IMAG_COMPONENT (D [col]) ;
+#endif
+ }
+ }
+
+ /* add all the entries from the rows of U */
+
+ 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] ;
+ }
+ }
+
+ for (k = npiv-1 ; k >= 0 ; k--)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* use row k of U */
+ /* ------------------------------------------------------------------ */
+
+ up = Uip [k] ;
+ ulen = Uilen [k] ;
+ newUchain = (up < 0) ;
+ if (newUchain)
+ {
+ up = -up ;
+ xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ;
+ }
+ else
+ {
+ xp = (Entry *) (Numeric->Memory + up) ;
+ }
+
+ xp += deg ;
+ for (j = deg-1 ; j >= 0 ; j--)
+ {
+ DEBUG4 ((" k "ID" col "ID" value", k, Pattern [j])) ;
+ col = Pattern [j] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ value = *(--xp) ;
+ EDEBUG4 (value) ;
+ DEBUG4 (("\n")) ;
+ if (IS_NONZERO (value))
+ {
+ p = --(Wi [col]) ;
+ Ui [p] = k ;
+ Ux [p] = REAL_COMPONENT (value) ;
+#ifdef COMPLEX
+ Uz [p] = IMAG_COMPONENT (value) ;
+#endif
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* make row k-1 of U in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ if (newUchain)
+ {
+ /* next row is a new Uchain */
+ deg = ulen ;
+ 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 ;
+ }
+ }
+ else
+ {
+ deg -= ulen ;
+ DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, 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 ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ DEBUG6 (("U matrix:")) ;
+ UMF_dump_col_matrix (Ux,
+#ifdef COMPLEX
+ Uz,
+#endif
+ Ui, Up, Numeric->n_row, n_col, Numeric->unz + Numeric->nnzpiv) ;
+#endif
+
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_get_symbolic.c b/src/sparse-matrix/umfpack/umfpack_get_symbolic.c
new file mode 100644
index 0000000..fb1d251
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_get_symbolic.c
@@ -0,0 +1,172 @@
+/* ========================================================================== */
+/* === UMFPACK_get_symbolic ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Gets the symbolic information held in the Symbolic object.
+ See umfpack_get_symbolic.h for a more detailed description.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_get_symbolic
+(
+ Int *p_n_row,
+ Int *p_n_col,
+ Int *p_nz,
+ Int *p_nfr,
+ Int *p_nchains,
+ Int Ptree [ ],
+ Int Qtree [ ],
+ Int Front_npivcol [ ],
+ Int Front_parent [ ],
+ Int Front_1strow [ ],
+ Int Front_leftmostdesc [ ],
+ Int Chain_start [ ],
+ Int Chain_maxrows [ ],
+ Int Chain_maxcols [ ],
+ void *SymbolicHandle
+)
+{
+ SymbolicType *Symbolic ;
+ Int k, n_row, n_col, nfr, nchains, *p ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check inputs */
+ /* ---------------------------------------------------------------------- */
+
+ Symbolic = (SymbolicType *) SymbolicHandle ;
+ if (!UMF_valid_symbolic (Symbolic))
+ {
+ return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* get contents of Symbolic */
+ /* ---------------------------------------------------------------------- */
+
+ n_row = Symbolic->n_row ;
+ n_col = Symbolic->n_col ;
+ nfr = Symbolic->nfr ;
+ nchains = Symbolic->nchains ;
+
+ if (p_n_row)
+ {
+ *p_n_row = n_row ;
+ }
+
+ if (p_n_col)
+ {
+ *p_n_col = n_col ;
+ }
+
+ if (p_nz)
+ {
+ *p_nz = Symbolic->nz ;
+ }
+
+ if (p_nfr)
+ {
+ *p_nfr = nfr ;
+ }
+
+ if (p_nchains)
+ {
+ *p_nchains = nchains ;
+ }
+
+ if (Ptree)
+ {
+ p = Symbolic->Rperm_init ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Ptree [k] = p [k] ;
+ }
+ }
+
+ if (Qtree)
+ {
+ p = Symbolic->Cperm_init ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Qtree [k] = p [k] ;
+ }
+ }
+
+ if (Front_npivcol)
+ {
+ p = Symbolic->Front_npivcol ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_npivcol [k] = p [k] ;
+ }
+ }
+
+ if (Front_parent)
+ {
+ p = Symbolic->Front_parent ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_parent [k] = p [k] ;
+ }
+ }
+
+ if (Front_1strow)
+ {
+ p = Symbolic->Front_1strow ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_1strow [k] = p [k] ;
+ }
+ }
+
+ if (Front_leftmostdesc)
+ {
+ p = Symbolic->Front_leftmostdesc ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_leftmostdesc [k] = p [k] ;
+ }
+ }
+
+ if (Chain_start)
+ {
+ p = Symbolic->Chain_start ;
+ for (k = 0 ; k <= nchains ; k++)
+ {
+ Chain_start [k] = p [k] ;
+ }
+ }
+
+ if (Chain_maxrows)
+ {
+ p = Symbolic->Chain_maxrows ;
+ for (k = 0 ; k < nchains ; k++)
+ {
+ Chain_maxrows [k] = p [k] ;
+ }
+ Chain_maxrows [nchains] = 0 ;
+ }
+
+ if (Chain_maxcols)
+ {
+ p = Symbolic->Chain_maxcols ;
+ for (k = 0 ; k < nchains ; k++)
+ {
+ Chain_maxcols [k] = p [k] ;
+ }
+ Chain_maxcols [nchains] = 0 ;
+ }
+
+ return (UMFPACK_OK) ;
+}
diff --git a/src/sparse-matrix/umfpack/umfpack_numeric.c b/src/sparse-matrix/umfpack/umfpack_numeric.c
new file mode 100644
index 0000000..c2f43c3
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_numeric.c
@@ -0,0 +1,736 @@
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* 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 usage: UMFPACK_numeric makes the heaviest usage of memory
+ space of all UMFPACK routines. Here is an outline of how it uses memory:
+
+ 1) calls UMF_malloc 14 times, to obtain temporary workspace of size f
+ Entry's and 2*(n_row+1) + 2*(n_col+1) + (n_col+n_inner+1) +
+ (nn+1) + 3*(c+1) + 2*(r+1) + max(r,c) + (nfr+1) integers
+ where f is the size of the working array used for the frontal
+ matrices, r is the maximum number of rows in the working array,
+ c is the maximum number of columns in the working array (f is
+ less than or equal to r*c, and typically f=r*c), 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 f Entry's and
+ about 7n + 3c + 2r + max(r,c) + nfr integers.
+
+ 2) calls UMF_malloc 10 times, for a total space of sizeof (NumericType)
+ bytes, 4*(n_row+1) + 4*(n_row+1) integers, and (n_inner+1) Entry's.
+ sizeof (NumericType) is a small constant. This space is part of the
+ permanent Numeric object (which holds the LU factors) and is not
+ freed on return via UMF_free unless an error occurs.
+
+ 3) calls UMF_malloc once, to allocate the variable-sized part of the
+ Numeric object, whose size in Units 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. The default value of
+ Control [UMFPACK_ALLOC_INIT] is 1.0. This request is reduced if it
+ fails. This object is not freed on return via UMF_free unless
+ an error occurs.
+
+ 4) 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. This is rare with the default control
+ setting of 1.0 (I've never observed it to happen, but it
+ theoretically could happen). During factorization, this block holds
+ the pattern and values of L and U at the top end, and the elements
+ (contibution blocks) at the bottom end.
+
+ For a square nonsingular matrix, the peak memory usage at this point
+ is roughly:
+
+ r*c + n Entry's
+ 15n + 3c + 2r + max(r,c) + nfr integers
+ plus peak size of the variable-sized part of the Numeric object
+ plus the size of the Symbolic object (2n to 9n integers)
+
+ where r is the maximum number of rows in the working array used
+ to hold the current frontal matrix, and c is the maximum number of
+ columns in the working array.
+
+ The peak value of the variable-sized object is estimated in
+ UMFPACK_*symbolic (Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]).
+ The size of the Symbolic object is in Info [UMFPACK_SYMBOLIC_SIZE],
+ and is between 2*n and 9*n integers.
+
+ 5) 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 nonzeros in the last pivot row.
+
+ 6) The variable-sized block is reduced to hold just L and U, via a call
+ to UMF_realloc, since the frontal matrices are no longer needed.
+
+ 7) This leaves a total of 11 or 12 objects allocated by UMF_malloc that
+ form the LU factorization. These remain if UMFPACK_numeric was
+ successful. Otherwise, they are all freed via UMF_free.
+ The final size of the Numeric object for a square nonsingular matrix
+ is roughly:
+
+ n Entry's
+ 8n integers
+ plus final size of the variable-sized part of the Numeric object
+
+ Dynamic memory usage of UMFPACK_free_numeric:
+
+ 1) It frees, via UMF_free, all 11 or 12 objects allocated for the
+ Numeric object, in a prior call to UMFPACK_numeric.
+
+*/
+
+/* ========================================================================== */
+
+#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
+) ;
+
+PRIVATE void free_work
+(
+ WorkType *Work
+) ;
+
+PRIVATE Int numeric_alloc
+(
+ NumericType **NumericHandle,
+ SymbolicType *Symbolic,
+ double alloc_init
+) ;
+
+PRIVATE void error
+(
+ NumericType **Numeric,
+ WorkType *Work
+) ;
+
+
+/* ========================================================================== */
+
+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 */
+ /* ---------------------------------------------------------------------- */
+
+ NumericType *Numeric ;
+ SymbolicType *Symbolic ;
+ WorkType WorkSpace, *Work ;
+ Int n_row, n_col, n_inner, newsize, i, status, *inew, npiv, ulen ;
+ Unit *mnew ;
+ double Info2 [UMFPACK_INFO], *Info, alloc_init, relax, relpt, tstart, tend,
+ relax2, relax3 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the amount of time used by the process so far */
+ /* ---------------------------------------------------------------------- */
+
+ tstart = umfpack_timer ( ) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize and check inputs */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ init_count = UMF_malloc_count ;
+#endif
+
+ if (Control)
+ {
+ /* use the Control array passed to us by the caller; look for NaN's */
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_PIVOT_TOLERANCE]))
+ {
+ relpt = UMFPACK_DEFAULT_PIVOT_TOLERANCE ;
+ }
+ else
+ {
+ relpt = Control [UMFPACK_PIVOT_TOLERANCE] ;
+ }
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_RELAXED_AMALGAMATION]))
+ {
+ relax = UMFPACK_DEFAULT_RELAXED_AMALGAMATION ;
+ }
+ else
+ {
+ relax = Control [UMFPACK_RELAXED_AMALGAMATION] ;
+ }
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_RELAXED2_AMALGAMATION]))
+ {
+ relax2 = UMFPACK_DEFAULT_RELAXED2_AMALGAMATION ;
+ }
+ else
+ {
+ relax2 = Control [UMFPACK_RELAXED2_AMALGAMATION] ;
+ }
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_RELAXED3_AMALGAMATION]))
+ {
+ relax3 = UMFPACK_DEFAULT_RELAXED3_AMALGAMATION ;
+ }
+ else
+ {
+ relax3 = Control [UMFPACK_RELAXED3_AMALGAMATION] ;
+ }
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_ALLOC_INIT]))
+ {
+ alloc_init = UMFPACK_DEFAULT_ALLOC_INIT ;
+ }
+ else
+ {
+ alloc_init = Control [UMFPACK_ALLOC_INIT] ;
+ }
+
+ }
+ else
+ {
+ /* no Control passed - use defaults instead */
+ relpt = UMFPACK_DEFAULT_PIVOT_TOLERANCE ;
+ relax = UMFPACK_DEFAULT_RELAXED_AMALGAMATION ;
+ relax2 = UMFPACK_DEFAULT_RELAXED2_AMALGAMATION ;
+ relax3 = UMFPACK_DEFAULT_RELAXED3_AMALGAMATION ;
+ alloc_init = UMFPACK_DEFAULT_ALLOC_INIT ;
+ }
+
+ relpt = MAX (0.0, MIN (relpt, 1.0)) ;
+ relax = MAX (0.0, relax) ;
+ relax2 = MAX (0.0, relax2) ;
+ relax3 = MAX (0.0, relax3) ;
+ alloc_init = MAX (0.0, alloc_init) ;
+
+ if (User_Info)
+ {
+ /* return Info in user's array */
+ Info = User_Info ;
+ for (i = UMFPACK_NUMERIC_SIZE ; i <= UMFPACK_NUMERIC_TIME ; 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) ;
+ }
+
+ n_row = Symbolic->n_row ;
+ n_col = Symbolic->n_col ;
+ n_inner = MIN (n_row, n_col) ;
+
+ Info [UMFPACK_STATUS] = UMFPACK_OK ;
+ Info [UMFPACK_NROW] = n_row ;
+ Info [UMFPACK_NCOL] = n_col ;
+ Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ;
+ Info [UMFPACK_NUMERIC_DEFRAG] = 0 ;
+ Info [UMFPACK_NUMERIC_REALLOC] = 0 ;
+ Info [UMFPACK_NUMERIC_COSTLY_REALLOC] = 0 ;
+
+ if (!Ap || !Ai || !Ax || !NumericHandle
+#ifdef COMPLEX
+ || !Az
+#endif
+ )
+ {
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ Work = &WorkSpace ;
+ Work->n_row = n_row ;
+ Work->n_col = n_col ;
+ Work->nfr = Symbolic->nfr ;
+ Work->maxfrsize = Symbolic->maxfrsize ;
+ Work->maxnrows = Symbolic->maxnrows ;
+ Work->maxncols = Symbolic->maxncols ;
+
+ if (!work_alloc (Work))
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Numeric, Work) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ ASSERT (UMF_malloc_count == init_count + 14) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate Numeric object */
+ /* ---------------------------------------------------------------------- */
+
+ if (!numeric_alloc (&Numeric, Symbolic, alloc_init))
+ {
+ 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 + 14 + 11) ;
+
+ /* set control parameters */
+ Numeric->relpt = relpt ;
+ Numeric->relax = relax ;
+ Numeric->relax2 = relax2 ;
+ Numeric->relax3 = relax3 ;
+ Numeric->alloc_init = alloc_init ;
+
+ DEBUG0 (("umf control: relpt %g relax [%g %g %g] init %g inc %g red %g\n",
+ relpt, relax, relax2, relax3, alloc_init,
+ UMF_REALLOC_INCREASE, UMF_REALLOC_REDUCTION)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* factorize */
+ /* ---------------------------------------------------------------------- */
+
+ status = UMF_kernel (Ap, Ai, Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ Numeric, Work, Symbolic) ;
+ Info [UMFPACK_STATUS] = status ;
+ Info [UMFPACK_VARIABLE_INIT] = Numeric->init_usage ;
+ if (status < 0)
+ {
+ /* out of memory, or pattern has changed */
+ error (&Numeric, Work) ;
+ return (status) ;
+ }
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ 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"\n", ulen)) ;
+ ASSERT (UMF_malloc_count == init_count + 11 + (ulen > 0)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* reduce Lpos, Lilen, Lip, Upos, Uilen and Uip to size npiv+1 */
+ /* ---------------------------------------------------------------------- */
+
+ /* This is only needed for rectangular or singular matrices. */
+
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ /* This is only needed for singular matrices, or if n_row < n_col. */
+ /* 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 */
+ /* ---------------------------------------------------------------------- */
+
+ 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 */
+ ACTUAL) ;
+
+ 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 ;
+
+ /* estimate of the recipricol of the condition number. */
+ if (SCALAR_IS_ZERO (Numeric->min_udiag)
+ || SCALAR_IS_ZERO (Numeric->max_udiag))
+ {
+ /* rcond is zero if there is any zero on the diagonal, */
+ /* even if NaN's are also present. */
+ 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_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 or 12 objects */
+ ASSERT (UMF_malloc_count == init_count + 11 + (ulen > 0)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the time used by UMFPACK_numeric */
+ /* ---------------------------------------------------------------------- */
+
+ tend = umfpack_timer ( ) ;
+ Info [UMFPACK_NUMERIC_TIME] = MAX (0, tend - tstart) ;
+
+ /* 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 n_row, n_col, n_inner, min_usage, trying ;
+ NumericType *Numeric ;
+ double nsize, bsize ;
+
+ ASSERT (Symbolic) ;
+
+ 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_fixed_size) */
+ 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_fixed_size) */
+ 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)) ;
+
+ Numeric->Memory = (Unit *) NULL ;
+ 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)
+ {
+ return (FALSE) ; /* out of memory */
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate initial Numeric->Memory for LU factors and elements */
+ /* ---------------------------------------------------------------------- */
+
+ nsize = (alloc_init * Symbolic->num_mem_usage_est) * (1.0 + MAX_EPSILON) ;
+ nsize = ceil (nsize) ;
+ min_usage = Symbolic->num_mem_init_usage ;
+
+ /* Numeric->Memory must be large enough for UMF_kernel_init */
+ /* double relop, but ignore NaN case. */
+ nsize = MAX (ceil ((double) min_usage * (1.0 + MAX_EPSILON)), 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) ; /* double relop, but ignore NaN case. */
+
+ 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
+)
+{
+ Int n_row, n_col, nn, n_inner, maxfrsize, maxnrows, maxncols, nfr ;
+
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ nn = MAX (n_row, n_col) ;
+ n_inner = MIN (n_row, n_col) ;
+ nfr = Work->nfr ;
+ maxfrsize = Work->maxfrsize ;
+ maxnrows = Work->maxnrows ;
+ maxncols = Work->maxncols ;
+
+ /* largest front will be maxnrows-by-maxncols, at most */
+ DEBUG1 (("Allocating frontal matrix, size "ID" ("ID"-by-"ID") saved: "ID
+ "\n", maxfrsize, maxnrows, maxncols,
+ (maxnrows * maxncols) - maxfrsize)) ;
+
+ /* 13 allocations, freed in free_work: */
+ /* accounted for in UMF_set_stats (work_usage) */
+ Work->Fx = (Entry *) UMF_malloc (maxfrsize, sizeof (Entry)) ;
+ Work->Frpos = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+ Work->Fcpos = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+ Work->Lpattern = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+ Work->Wp = (Int *) UMF_malloc (nn + 1, sizeof (Int)) ;
+ Work->Frows = (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 (MAX (maxnrows, maxncols) + 1, sizeof (Int));
+ Work->Wm = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+ Work->E = (Int *) UMF_malloc (n_col + n_inner + 1, sizeof (Int)) ;
+ Work->Front_new1strow = (Int *) UMF_malloc (nfr + 1, sizeof (Int)) ;
+
+ /* 1 allocation, may become part of Numeric (if singular or rectangular): */
+ Work->Upattern = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+
+ return (Work->Fx && Work->Frpos
+ && Work->Fcpos && Work->Lpattern && Work->Upattern
+ && Work->E && Work->Frows && Work->Fcols && Work->Wio
+ && Work->Woi && Work->Woo && Work->Wm && Work->Wp
+ && Work->Front_new1strow) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+ WorkType *Work
+)
+{
+ if (Work)
+ {
+
+ /* free 13 or 14 objects (Upattern may already be gone) */
+ Work->Fx = (Entry *) UMF_free ((void *) Work->Fx) ;
+ 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->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) ;
+
+ }
+}
+
+
+/* ========================================================================== */
+/* === 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) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_qsymbolic.c b/src/sparse-matrix/umfpack/umfpack_qsymbolic.c
new file mode 100644
index 0000000..061d3ba
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_qsymbolic.c
@@ -0,0 +1,1347 @@
+/* ========================================================================== */
+/* === UMFPACK_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Performs a symbolic factorization.
+ See umfpack_qsymbolic.h and umfpack_symbolic.h for details.
+
+ Dynamic memory usage of UMFPACK_qsymbolic:
+
+ 1) calls UMF_malloc 6 times, for workspace of total size (C + 5*n_col)
+ integers. The value of C is determined by the macro
+ UMF_COLAMD_RECOMMENDED. It is roughly
+ max (2*nz, 3*n_col) + 8*n_col + 6*n_row + n_col + nz/5, or typically
+ about 2.2*nz + 9*n_col + 6*n_row, where nz is the number of entries in
+ A. If A is square, this is 2.2*nz + 15*n.
+
+ 2) three more calls to UMF_malloc are made, for a total space of
+ (n_row+1 + n_col+1) integers + sizeof (SymbolicType).
+ sizeof (SymbolicType) is a small constant. This space is part of the
+ Symbolic object and is not freed unless an error occurs. The analysis
+ (UMF_colamd and/or UMF_analyze) is then performed.
+ This is about 2n if A is square.
+
+ 3) UMF_malloc is called 7 times, for a total workspace of
+ (4*(nfr+1)+3*(nchains+1)) integers, where nfr is the total number of
+ frontal matrices and nchains is the total number of frontal matrix
+ chains, and where nchains <= nfr <= n_col. This space is part of the
+ Symbolic object and is not free'd unless an error occurs. This is
+ between 7 and about 7n integers when A is square.
+
+ Thus, the peak memory usage of UMFPACK_symbolic occurs at this point.
+ For a square matrix, it is at most about (2.2*nz + 24*n) integers for
+ temporary workspace, plus between 2*n and 9*n integers for the final
+ Symbolic object.
+
+ 4) The 6 workspace objects allocated in step (1) are free'd via
+ UMF_free. The final Symbolic object consists of 10 allocated objects.
+ Its final total size is lies roughly between 2*n and 9*n for a square
+ matrix. If an error occurs, all 10 objects are free'd via UMF_free.
+
+ Dynamic memory usage of UMFPACK_free_symbolic:
+
+ 1) All 10 objects comprising the Symbolic object are free'd via UMF_free.
+
+*/
+
+/* ========================================================================== */
+
+#include "umf_internal.h"
+#include "umf_symbolic_usage.h"
+#include "umf_colamd.h"
+#include "umf_set_stats.h"
+#include "umf_analyze.h"
+#include "umf_transpose.h"
+#include "umf_is_permutation.h"
+#include "umf_kernel_init_usage.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+typedef struct /* SWorkType */
+{
+ Int *Front_npivcol ;
+ Int *Front_nrows ;
+ Int *Front_ncols ;
+ Int *Front_parent ;
+ Int *Front_cols ; /* in UMF_colamd only */
+ Int *Ci ;
+
+} SWorkType ;
+
+PRIVATE void free_work
+(
+ SWorkType *SWork
+) ;
+
+PRIVATE void error
+(
+ SymbolicType **Symbolic,
+ SWorkType *SWork
+) ;
+
+#define SYM_WORK_USAGE(n_col,Clen) (DUNITS (Int, Clen) + 5*DUNITS (Int, n_col))
+
+/* required size of Ci for code that calls UMF_transpose and UMF_analyze below*/
+#define UMF_ANALYZE_CLEN(nz,n_row,n_col,nn) \
+ ((n_col) + MAX ((nz),1) + 3*(nn)+1 + (n_col))
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_qsymbolic
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const Int Q [ ],
+ void **SymbolicHandle,
+ const double Control [UMFPACK_CONTROL],
+ double User_Info [UMFPACK_INFO]
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int colamd_ok, i, nz, maxfrsize, s, j, newj, status, maxoldpiv, chain_npiv,
+ maxnrows, maxncols, nfr, col, nchains, maxrows, maxcols, p, nb, nn,
+ *Chain_start, *Chain_maxrows, *Chain_maxcols, *Front_npivcol, *Ci,
+ Clen, colamd_stats [COLAMD_STATS], fpiv, frows, fcols, n_inner,
+ child, cr, cc, cp, parent, *Link, *Row_degree, row, *Front_parent,
+ head_usage, tail_usage, max_usage, analyze_compactions,
+ lf, uf, init_tail_usage, k, do_colamd, do_UMF_analyze, too_large,
+ fpivcol, fallrows, fallcols, *InFront, *F1,
+ *Front_1strow, f1rows, kk, *Cperm_init, *Rperm_init, newrow,
+ *Front_leftmostdesc, Clen_analyze ;
+ double knobs [COLAMD_KNOBS], flops, f, r, c, tstart, tend,
+ *Info, Info2 [UMFPACK_INFO], drow, dcol, dusage, dlf, duf, dmax_usage,
+ dhead_usage, dh, dlnz, dunz, dmaxfrsize, dClen, dClen_analyze ;
+ Int nempty_row, nempty_col ;
+ SymbolicType *Symbolic ;
+ SWorkType SWorkSpace, *SWork ;
+
+#ifndef NDEBUG
+ double f2 ;
+ Int lf2, uf2 ;
+ UMF_dump_start ( ) ;
+ init_count = UMF_malloc_count ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get the amount of time used by the process so far */
+ /* ---------------------------------------------------------------------- */
+
+ tstart = umfpack_timer ( ) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check input parameters */
+ /* ---------------------------------------------------------------------- */
+
+ if (Control)
+ {
+ /* use the Control array passed to us by the caller. */
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_DENSE_ROW]))
+ {
+ drow = UMFPACK_DEFAULT_DENSE_ROW ;
+ }
+ else
+ {
+ drow = Control [UMFPACK_DENSE_ROW] ;
+ }
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_DENSE_COL]))
+ {
+ dcol = UMFPACK_DEFAULT_DENSE_COL ;
+ }
+ else
+ {
+ dcol = Control [UMFPACK_DENSE_COL] ;
+ }
+
+ if (SCALAR_IS_NAN (Control [UMFPACK_BLOCK_SIZE]))
+ {
+ nb = UMFPACK_DEFAULT_BLOCK_SIZE ;
+ }
+ else
+ {
+ nb = (Int) Control [UMFPACK_BLOCK_SIZE] ;
+ }
+
+ }
+ else
+ {
+ /* no Control passed - use defaults instead */
+ drow = UMFPACK_DEFAULT_DENSE_ROW ;
+ dcol = UMFPACK_DEFAULT_DENSE_COL ;
+ nb = UMFPACK_DEFAULT_BLOCK_SIZE ;
+ }
+
+ nb = MAX (1, nb) ;
+ DEBUG0 (("nb = "ID"\n", nb)) ;
+
+ if (User_Info)
+ {
+ /* 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 ;
+ }
+
+ nn = MAX (n_row, n_col) ;
+ n_inner = MIN (n_row, n_col) ;
+
+ Info [UMFPACK_STATUS] = UMFPACK_OK ;
+ Info [UMFPACK_NROW] = n_row ;
+ Info [UMFPACK_NCOL] = n_col ;
+ Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ;
+ Info [UMFPACK_SIZE_OF_INT] = (double) (sizeof (int)) ;
+ Info [UMFPACK_SIZE_OF_LONG] = (double) (sizeof (long)) ;
+ Info [UMFPACK_SIZE_OF_POINTER] = (double) (sizeof (void *)) ;
+ Info [UMFPACK_SIZE_OF_ENTRY] = (double) (sizeof (Entry)) ;
+ Info [UMFPACK_SYMBOLIC_DEFRAG] = 0 ;
+
+ if (!Ai || !Ap || !SymbolicHandle)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ *SymbolicHandle = (void *) NULL ;
+
+ if (n_row <= 0 || n_col <= 0) /* n_row, n_col must be > 0 */
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_n_nonpositive ;
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+
+ nz = Ap [n_col] ;
+ DEBUG0 (("In UMFPACK_symbolic, n_row "ID" n_col "ID" nz "ID"\n",
+ n_row, n_col, nz)) ;
+ Info [UMFPACK_NZ] = nz ;
+ if (nz < 0)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_nz_negative ;
+ return (UMFPACK_ERROR_nz_negative) ;
+ }
+
+ if (Q)
+ {
+ do_colamd = FALSE ;
+ }
+ else
+ {
+ do_colamd = TRUE ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* determine amount of memory required for UMFPACK_symbolic */
+ /* ---------------------------------------------------------------------- */
+
+ /* The size of Clen required for UMF_colamd is always larger than */
+ /* UMF_analyze, but the max is included here in case that changes in */
+ /* future versions. */
+
+ dClen = UMF_COLAMD_RECOMMENDED ((double) nz, (double) n_row,
+ (double) n_col) ;
+ dClen_analyze = UMF_ANALYZE_CLEN ((double) nz, (double) n_row,
+ (double) n_col, (double) nn) ;
+ dClen = MAX (dClen, dClen_analyze) ;
+ too_large = INT_OVERFLOW (dClen * sizeof (Int)) ;
+
+ if (too_large)
+ {
+ /* Problem is too large for array indexing (Ci [i]) with an Int i. */
+ /* Cannot even analyze the problem to determine upper bounds on */
+ /* memory usage. Need to use the long integer version, umfpack_*l_*. */
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_problem_too_large ;
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+ SYM_WORK_USAGE (n_col, dClen) +
+ UMF_symbolic_usage (n_row, n_col, n_col, n_col) ;
+ return (UMFPACK_ERROR_problem_too_large) ;
+ }
+
+ Clen = UMF_COLAMD_RECOMMENDED (nz, n_row, n_col) ;
+ Clen_analyze = UMF_ANALYZE_CLEN (nz, n_row, n_col, nn) ;
+ Clen = MAX (Clen, Clen_analyze) ;
+
+ /* worst case total memory usage for UMFPACK_symbolic (revised below) */
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+ SYM_WORK_USAGE (n_col, Clen) +
+ UMF_symbolic_usage (n_row, n_col, n_col, n_col) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate workspace */
+ /* ---------------------------------------------------------------------- */
+
+ Symbolic = (SymbolicType *) NULL ;
+ SWork = &SWorkSpace ; /* used for UMFPACK_symbolic only */
+
+ /* Note that SWork->Front_* does not include the dummy placeholder front. */
+ /* This space is accounted for by the SYM_WORK_USAGE (n_col, Clen) macro. */
+ SWork->Ci = (Int *) UMF_malloc (Clen, sizeof (Int)) ;
+ SWork->Front_npivcol = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SWork->Front_nrows = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SWork->Front_ncols = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SWork->Front_parent = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SWork->Front_cols = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+
+ if (!SWork->Ci || !SWork->Front_npivcol || !SWork->Front_nrows ||
+ !SWork->Front_ncols || !SWork->Front_parent || !SWork->Front_cols)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the first part of the Symbolic object (header and Cperm_init) */
+ /* ---------------------------------------------------------------------- */
+
+ Symbolic = (SymbolicType *) UMF_malloc (1, sizeof (SymbolicType)) ;
+
+ if (!Symbolic)
+ {
+ /* If we fail here, Symbolic is NULL and thus it won't be */
+ /* dereferenced by UMFPACK_free_symbolic, as called by error ( ). */
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ /* We now know that Symbolic has been allocated */
+ Symbolic->valid = 0 ;
+ Symbolic->Chain_start = (Int *) NULL ;
+ Symbolic->Chain_maxrows = (Int *) NULL ;
+ Symbolic->Chain_maxcols = (Int *) NULL ;
+ Symbolic->Front_npivcol = (Int *) NULL ;
+ Symbolic->Front_parent = (Int *) NULL ;
+ Symbolic->Front_1strow = (Int *) NULL ;
+ Symbolic->Front_leftmostdesc = (Int *) NULL ;
+
+ Symbolic->Cperm_init = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Symbolic->Rperm_init = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+ Cperm_init = Symbolic->Cperm_init ;
+ Rperm_init = Symbolic->Rperm_init ;
+
+ if (!Symbolic->Cperm_init || !Symbolic->Rperm_init)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ DEBUG0 (("(1)Symbolic UMF_malloc_count - init_count = "ID"\n",
+ UMF_malloc_count - init_count)) ;
+ ASSERT (UMF_malloc_count == init_count + 9) ;
+
+ Symbolic->n_row = n_row ;
+ Symbolic->n_col = n_col ;
+ Symbolic->nz = nz ;
+ Symbolic->drow = drow ;
+ Symbolic->dcol = dcol ;
+ Symbolic->nb = nb ;
+
+ /* ---------------------------------------------------------------------- */
+ /* use colamd or input column ordering Q */
+ /* ---------------------------------------------------------------------- */
+
+ if (do_colamd)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* copy the matrix into colamd workspace (colamd destroys its input) */
+ /* ------------------------------------------------------------------ */
+
+ Ci = SWork->Ci ;
+ for (i = 0 ; i < nz ; i++)
+ {
+ DEBUG5 (("Ai "ID": "ID"\n", i, Ai [i])) ;
+ Ci [i] = Ai [i] ;
+ }
+
+ /* load the column pointers into Cperm_init [0..n_col] */
+ for (col = 0 ; col <= n_col ; col++)
+ {
+ DEBUG5 (("Ap "ID": "ID"\n", col, Ap [col])) ;
+ Cperm_init [col] = Ap [col] ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* set UMF_colamd defaults */
+ /* ------------------------------------------------------------------ */
+
+ UMF_colamd_set_defaults (knobs) ;
+ knobs [COLAMD_DENSE_ROW] = drow ;
+ knobs [COLAMD_DENSE_COL] = dcol ;
+
+ /* ------------------------------------------------------------------ */
+ /* check input matrix and find the initial column pre-ordering */
+ /* ------------------------------------------------------------------ */
+
+ colamd_ok = UMF_colamd (n_row, n_col, Clen, SWork->Ci,
+ Cperm_init, knobs, colamd_stats,
+ SWork->Front_npivcol,
+ SWork->Front_nrows,
+ SWork->Front_ncols,
+ SWork->Front_parent,
+ /* used in UMF_colamd only: */ SWork->Front_cols,
+ &nfr) ;
+
+ /* get number of truly empty rows and columns */
+ nempty_row = colamd_stats [COLAMD_EMPTY_ROW] ;
+ nempty_col = colamd_stats [COLAMD_EMPTY_COL] ;
+
+ if (!colamd_ok)
+ {
+ /* This will be modified below. It is not (yet) an internal */
+ /* error. It is only an internal error if is it not modified */
+ /* below (colamd_stats missing). */
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_internal_error ;
+ }
+
+ s = colamd_stats [COLAMD_STATUS] ;
+
+ if (s == COLAMD_OK)
+ {
+ status = UMFPACK_OK ;
+ }
+ else if (s == COLAMD_ERROR_jumbled_matrix)
+ {
+ status = UMFPACK_ERROR_jumbled_matrix ;
+ }
+ else if (s == COLAMD_ERROR_p0_nonzero)
+ {
+ status = UMFPACK_ERROR_Ap0_nonzero ;
+ }
+ else if (s == COLAMD_ERROR_row_index_out_of_bounds)
+ {
+ status = UMFPACK_ERROR_row_index_out_of_bounds ;
+ }
+ else if (s == COLAMD_ERROR_col_length_negative)
+ {
+ status = UMFPACK_ERROR_col_length_negative ;
+ }
+ else
+ {
+ /* these errors "cannot" happen */
+ /* COLAMD_ERROR_A_too_small */
+ /* COLAMD_ERROR_A_not_present */
+ /* COLAMD_ERROR_p_not_present */
+ /* COLAMD_ERROR_out_of_memory */
+ /* COLAMD_ERROR_internal_error */
+ /* COLAMD_ERROR_nrow_negative */
+ /* COLAMD_ERROR_ncol_negative */
+ /* COLAMD_ERROR_nnz_negative */
+ status = UMFPACK_ERROR_internal_error ;
+ }
+
+ Info [UMFPACK_STATUS] = status ;
+ if (status != UMFPACK_OK)
+ {
+ error (&Symbolic, SWork) ;
+ return (status) ;
+ }
+
+ Info [UMFPACK_NDENSE_ROW] = colamd_stats [COLAMD_DENSE_ROW] ;
+ Info [UMFPACK_NEMPTY_ROW] = colamd_stats [COLAMD_EMPTY_ROW]
+ + colamd_stats [COLAMD_NEWLY_EMPTY_ROW] ;
+ Info [UMFPACK_NDENSE_COL] = colamd_stats [COLAMD_DENSE_COL] ;
+ Info [UMFPACK_NEMPTY_COL] = colamd_stats [COLAMD_EMPTY_COL]
+ + colamd_stats [COLAMD_NEWLY_EMPTY_COL] ;
+ Info [UMFPACK_SYMBOLIC_DEFRAG] = colamd_stats [COLAMD_DEFRAG_COUNT];
+
+ /* re-analyze if any "dense" rows or cols ignored by UMF_colamd */
+ do_UMF_analyze =
+ colamd_stats [COLAMD_DENSE_ROW] > 0 ||
+ colamd_stats [COLAMD_DENSE_COL] > 0 ;
+
+#ifndef NDEBUG
+ for (col = 0 ; col < n_col ; col++)
+ {
+ DEBUG1 (("Cperm_init ["ID"] = "ID"\n", col, Cperm_init[col]));
+ }
+ /* make sure colamd returned a valid permutation */
+ ASSERT (Cperm_init) ;
+ ASSERT (UMF_is_permutation (Cperm_init, SWork->Ci, n_col, n_col)) ;
+#endif
+
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* do not call colamd - use input Q instead */
+ /* ------------------------------------------------------------------ */
+
+ Int length ;
+
+ /* use Ci as workspace to check input permutation */
+ if (!UMF_is_permutation (Q, SWork->Ci, n_col, n_col))
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_permutation ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_invalid_permutation) ;
+ }
+
+ if (Ap [0] != 0)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_Ap0_nonzero ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_Ap0_nonzero) ;
+ }
+
+ nempty_col = 0 ;
+
+ /* check Ap input */
+ for (j = 0 ; j < n_col ; j++)
+ {
+ length = Ap [j+1] - Ap [j] ;
+ if (length == 0)
+ {
+ /* this is an empty column */
+ DEBUG1 (("Original empty column: "ID"\n", j)) ;
+ nempty_col++ ;
+ }
+ if (length < 0)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_col_length_negative ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_col_length_negative) ;
+ }
+ }
+
+ Info [UMFPACK_NDENSE_ROW] = 0 ;
+ Info [UMFPACK_NEMPTY_ROW] = 0 ; /* this is fixed below */
+ Info [UMFPACK_NDENSE_COL] = 0 ;
+ Info [UMFPACK_NEMPTY_COL] = nempty_col ;
+
+ if (nempty_col == 0)
+ {
+ /* copy the user's input permutation */
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Cperm_init [k] = Q [k] ;
+ }
+ }
+ else
+ {
+ /* partition the user's input permutation */
+
+ /* move empty columns last */
+ k = n_col ;
+ for (j = n_col-1 ; j >= 0 ; j--)
+ {
+ col = Q [j] ;
+ length = Ap [col+1] - Ap [col] ;
+ if (length == 0)
+ {
+ Cperm_init [--k] = col ;
+ DEBUG1 (("Moving empty col "ID" last: "ID"\n", col, k)) ;
+ }
+ }
+ ASSERT (n_col-k == nempty_col) ;
+
+ /* move remaining columns first */
+ k = 0 ;
+ for (j = 0 ; j < n_col ; j++)
+ {
+ col = Q [j] ;
+ length = Ap [col+1] - Ap [col] ;
+ if (length != 0)
+ {
+ DEBUG1 (("Non empty col "ID" at: "ID"\n", col, k)) ;
+ Cperm_init [k++] = col ;
+ }
+ }
+ }
+
+ do_UMF_analyze = TRUE ;
+
+ }
+
+ Cperm_init [n_col] = EMPTY ; /* unused in Cperm_init */
+
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG3 (("Cperm_init column permutation:\n")) ;
+ ASSERT (UMF_is_permutation (Cperm_init, SWork->Ci, n_col, n_col)) ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ DEBUG3 ((ID"\n", Cperm_init [k])) ;
+ }
+ /* ensure that empty columns have been placed last in A (:,Cperm_init) */
+ for (newj = 0 ; newj < n_col ; newj++)
+ {
+ /* empty columns will be last in A (:, Cperm_init (1:n_col)) */
+ j = Cperm_init [newj] ;
+ ASSERT (IMPLIES (newj >= n_col-nempty_col, Ap [j+1] - Ap [j] == 0)) ;
+ ASSERT (IMPLIES (newj < n_col-nempty_col, Ap [j+1] - Ap [j] > 0)) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* analyze, using the given ordering, or using colamd's ordering */
+ /* ---------------------------------------------------------------------- */
+
+ if (do_UMF_analyze)
+ {
+
+ Int *W, *Bp, *Bi, *Cperm2, ok, ilast, *P, Clen2, bsize, Clen0 ;
+
+ /* ------------------------------------------------------------------ */
+ /* Ci [0 .. Clen-1] holds the following work arrays:
+
+ first Clen0 entries empty space, where Clen0 =
+ Clen - (nn+1 + 2*nn + n_col)
+ and Clen0 >= nz + n_col
+ next nn+1 entries Bp [0..nn]
+ next nn entries Link [0..nn-1]
+ next nn entries W [0..nn-1]
+ last n_col entries Cperm2 [0..n_col-1]
+ */
+
+ Ci = SWork->Ci ;
+ Clen0 = Clen - (nn+1 + 2*nn + n_col) ;
+ Bp = Ci + Clen0 ;
+ Link = Bp + (nn+1) ;
+ W = Link + nn ;
+ Cperm2 = W + nn ;
+ ASSERT (Cperm2 + n_col == Ci + Clen) ;
+ ASSERT (Clen0 >= nz + n_col) ;
+
+ /* ------------------------------------------------------------------ */
+ /* P = order that rows will be used in UMF_analyze */
+ /* ------------------------------------------------------------------ */
+
+ /* use W to mark rows, and use Link for row permutation P [ [ */
+ for (row = 0 ; row < n_row ; row++)
+ {
+ W [row] = FALSE ;
+ }
+ P = Link ;
+
+ k = 0 ;
+ for (newj = 0 ; newj < n_col ; newj++)
+ {
+ /* empty columns will be last in A (:,Cperm_init) */
+ j = Cperm_init [newj] ;
+ ilast = -1 ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ row = Ai [p] ;
+ if (row < 0 || row >= n_row)
+ {
+ Info [UMFPACK_STATUS] =
+ UMFPACK_ERROR_row_index_out_of_bounds ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_row_index_out_of_bounds) ;
+ }
+ if (row <= ilast)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_jumbled_matrix ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_jumbled_matrix) ;
+ }
+ if (!W [row])
+ {
+ /* this row has just been see for the first time */
+ W [row] = TRUE ;
+ P [k++] = row ;
+ }
+ ilast = row ;
+ }
+ }
+
+ /* If the matrix has truly empty rows, then P will not be */
+ /* complete, and visa versa. The matrix is structurally singular. */
+ ASSERT (IMPLIES (do_colamd, nempty_row == n_row-k)) ;
+ nempty_row = n_row - k ;
+ Info [UMFPACK_NEMPTY_ROW] = nempty_row ;
+ if (k < n_row)
+ {
+ /* complete P by putting empty rows last in their natural order, */
+ /* rather than declaring an error (the matrix is singular) */
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (!W [row])
+ {
+ /* W [row] = TRUE ; (not required) */
+ P [k++] = row ;
+ }
+ }
+ }
+
+ /* contents of W no longer needed ] */
+
+#ifndef NDEBUG
+ DEBUG3 (("Induced row permutation:\n")) ;
+ ASSERT (k == n_row) ;
+ ASSERT (UMF_is_permutation (P, W, n_row, n_row)) ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ DEBUG3 ((ID"\n", P [k])) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* B = row-form of the pattern of A (P, Cperm_init (1:n_col)) */
+ /* ------------------------------------------------------------------ */
+
+ /* Ci [0 .. Clen-1] holds the following work arrays:
+
+ first Clen2 entries empty space, must be at least >= n_col
+ next max (nz,1) Bi [0..max (nz,1)-1]
+ next nn+1 entries Bp [0..nn]
+ next nn entries Link [0..nn-1]
+ next nn entries W [0..nn-1]
+ last n_col entries Cperm2 [0..n_col-1]
+
+ This memory usage is accounted for by the UMF_ANALYZE_CLEN
+ macro.
+ */
+
+ Clen2 = Clen0 ;
+ bsize = MAX (nz, 1) ;
+ Clen2 -= bsize ;
+ Bi = Ci + Clen2 ;
+ ASSERT (Clen2 >= n_col) ;
+
+ /* skip error test (already done, above). Do pattern only. */
+ (void) UMF_transpose (n_row, n_col, Ap, Ai, (double *) NULL, P,
+ Cperm_init, n_col - nempty_col, Bp, Bi, (double *) NULL, W, FALSE
+#ifdef COMPLEX
+ , (double *) NULL, (double *) NULL, FALSE
+#endif
+ ) ;
+
+ /* contents of P (same as Link) and W not needed */
+ /* still need Link and W as work arrays, though ] */
+
+ ASSERT (Bp [0] == 0) ;
+ ASSERT (Bp [n_row] == nz) ;
+
+ /* increment Bp to point into Ci, not Bi */
+ for (i = 0 ; i <= n_row ; i++)
+ {
+ Bp [i] += Clen2 ;
+ }
+ ASSERT (Bp [0] == Clen0 - bsize) ;
+ ASSERT (Bp [n_row] <= Clen0) ;
+
+ /* Ci [0 .. Clen-1] holds the following work arrays:
+
+ first Clen0 entries Ci [0 .. Clen0-1], where the col indices
+ of B are at the tail end of this part,
+ and Bp [0] = Clen2 >= n_col. Note
+ that Clen0 = Clen2 + max (nz,1).
+ next nn+1 entries Bp [0..nn]
+ next nn entries Link [0..nn-1]
+ next nn entries W [0..nn-1]
+ last n_col entries Cperm2 [0..n_col-1]
+ */
+
+ /* ------------------------------------------------------------------ */
+ /* analyze */
+ /* ------------------------------------------------------------------ */
+
+ /* only analyze the non-empty part of the matrix */
+ ok = UMF_analyze (n_row - nempty_row, n_col - nempty_col,
+ Ci, Bp, Cperm2, W, Link,
+ SWork->Front_ncols, SWork->Front_nrows, SWork->Front_npivcol,
+ SWork->Front_parent, &nfr, &analyze_compactions) ;
+ if (!ok)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_internal_error ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_internal_error) ;
+ }
+ Info [UMFPACK_SYMBOLIC_DEFRAG] += analyze_compactions ;
+
+ /* ------------------------------------------------------------------ */
+ /* combine the input permutation and UMF_analyze's permutation */
+ /* ------------------------------------------------------------------ */
+
+ /* Cperm2 is the column etree post-ordering */
+ ASSERT (UMF_is_permutation (Cperm2, W,
+ n_col-nempty_col, n_col-nempty_col)) ;
+
+ /* Note that the empty columns remain at the end of Cperm_init */
+ for (k = 0 ; k < n_col - nempty_col ; k++)
+ {
+ W [k] = Cperm_init [Cperm2 [k]] ;
+ }
+
+ for (k = 0 ; k < n_col - nempty_col ; k++)
+ {
+ Cperm_init [k] = W [k] ;
+ }
+
+ ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ;
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the size of the Symbolic object */
+ /* ---------------------------------------------------------------------- */
+
+ nchains = 0 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ if (SWork->Front_parent [i] != i+1)
+ {
+ nchains++ ;
+ }
+ }
+
+ Symbolic->nchains = nchains ;
+ Symbolic->nfr = nfr ;
+
+ /* final size of Symbolic object */
+ Info [UMFPACK_SYMBOLIC_SIZE] =
+ UMF_symbolic_usage (n_row, n_col, nchains, nfr) ;
+
+ /* actual peak memory usage for UMFPACK_symbolic (actual nfr, nchains) */
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+ SYM_WORK_USAGE (n_col, Clen) + Info [UMFPACK_SYMBOLIC_SIZE] ;
+ Symbolic->peak_sym_usage = Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] ;
+
+ DEBUG0 (("Number of fronts: "ID"\n", nfr)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the second part of the Symbolic object (Front_*, Chain_*) */
+ /* ---------------------------------------------------------------------- */
+
+ /* Note that Symbolic->Front_* does include the dummy placeholder front */
+ Symbolic->Front_npivcol = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+ Symbolic->Front_parent = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+ Symbolic->Front_1strow = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+ Symbolic->Front_leftmostdesc = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ;
+
+ Symbolic->Chain_start = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ;
+ Symbolic->Chain_maxrows = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ;
+ Symbolic->Chain_maxcols = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ;
+
+ if (!Symbolic->Front_npivcol || !Symbolic->Front_parent ||
+ !Symbolic->Front_1strow || !Symbolic->Front_leftmostdesc ||
+ !Symbolic->Chain_start || !Symbolic->Chain_maxrows ||
+ !Symbolic->Chain_maxcols)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ DEBUG0 (("(2)Symbolic UMF_malloc_count - init_count = "ID"\n",
+ UMF_malloc_count - init_count)) ;
+ ASSERT (UMF_malloc_count == init_count + 16) ;
+
+ Front_npivcol = Symbolic->Front_npivcol ;
+ Front_parent = Symbolic->Front_parent ;
+ Front_1strow = Symbolic->Front_1strow ;
+ Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+
+ Chain_start = Symbolic->Chain_start ;
+ Chain_maxrows = Symbolic->Chain_maxrows ;
+ Chain_maxcols = Symbolic->Chain_maxcols ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find row degrees and assign rows to fronts */
+ /* ---------------------------------------------------------------------- */
+
+ /* Use SWork->Ci as temporary workspace for Row_degree, InFront, and F1 */
+ Row_degree = SWork->Ci ; /* [ of size n_row */
+ InFront = Row_degree + n_row ; /* [ of size n_row */
+ F1 = InFront + n_row ; /* [ of size nfr+1 */
+ ASSERT (Clen >= 2*n_row + nfr+1) ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Row_degree [row] = 0 ;
+ InFront [row] = nfr ; /* empty rows go to dummy front nfr */
+ }
+
+ newj = 0 ;
+ k = 0 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ fpivcol = SWork->Front_npivcol [i] ;
+ DEBUG1 (("Front "ID" k "ID" npivcol "ID" nrows "ID" ncols "ID"\n",
+ i, k, fpivcol, SWork->Front_nrows [i], SWork->Front_ncols [i])) ;
+ k += fpivcol ;
+
+ /* copy Front info into Symbolic object from SWork */
+ Front_npivcol [i] = fpivcol ;
+ Front_parent [i] = SWork->Front_parent [i] ;
+
+ f1rows = 0 ;
+
+ /* for all pivot columns in front i */
+ for (kk = 0 ; kk < fpivcol ; kk++, newj++)
+ {
+ j = Cperm_init [newj] ;
+ ASSERT (IMPLIES (newj >= n_col-nempty_col, Ap [j+1] - Ap [j] == 0));
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ row = Ai [p] ;
+ if (Row_degree [row] == 0)
+ {
+ /* this row belongs to front i */
+ DEBUG1 ((" Row "ID" in Front "ID"\n", row, i)) ;
+ InFront [row] = i ;
+ f1rows++ ;
+ }
+ Row_degree [row]++ ;
+ }
+ }
+ Front_1strow [i] = f1rows ;
+ }
+
+ /* assign empty columns to dummy placehold front nfr */
+ DEBUG1 (("Dummy Cols in Front "ID" :: "ID"\n", nfr, n_col-k)) ;
+ Front_npivcol [nfr] = n_col - k ;
+ Front_parent [nfr] = EMPTY ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find initial row permutation */
+ /* ---------------------------------------------------------------------- */
+
+ /* determine the first row in each front (in the new row ordering) */
+ k = 0 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ f1rows = Front_1strow [i] ;
+ DEBUG1 (("Front "ID" :: npivcol "ID" parent "ID,
+ i, Front_npivcol [i], Front_parent [i])) ;
+ DEBUG1 ((" 1st rows in Front "ID" : "ID"\n", i, f1rows)) ;
+ Front_1strow [i] = k ;
+ k += f1rows ;
+ }
+
+ /* assign empty rows to dummy placehold front nfr */
+ DEBUG1 (("Rows in Front "ID" (dummy): "ID"\n", nfr, n_row-k)) ;
+ Front_1strow [nfr] = k ;
+ DEBUG1 (("nfr "ID" 1strow[nfr] "ID" nrow "ID"\n", nfr, k, n_row)) ;
+
+ for (i = 0 ; i <= nfr ; i++)
+ {
+ F1 [i] = Front_1strow [i] ;
+ }
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ i = InFront [row] ;
+ newrow = F1 [i]++ ;
+ Rperm_init [newrow] = row ;
+ }
+ Rperm_init [n_row] = EMPTY ; /* unused */
+
+#ifndef NDEBUG
+ for (k = 0 ; k < n_row ; k++)
+ {
+ DEBUG2 (("Rperm_init ["ID"] = "ID"\n", k, Rperm_init [k])) ;
+ }
+#endif
+
+ /* ] done using F1 */
+ /* ] done using InFront */
+
+ /* ---------------------------------------------------------------------- */
+ /* find the leftmost descendant of each front */
+ /* ---------------------------------------------------------------------- */
+
+ for (i = 0 ; i <= nfr ; i++)
+ {
+ Front_leftmostdesc [i] = EMPTY ;
+ }
+
+ for (i = 0 ; i < nfr ; i++)
+ {
+ /* start at i and walk up the tree */
+ DEBUG2 (("Walk up front tree from "ID"\n", i)) ;
+ j = i ;
+ while (j != EMPTY && Front_leftmostdesc [j] == EMPTY)
+ {
+ DEBUG3 ((" Leftmost desc of "ID" is "ID"\n", j, i)) ;
+ Front_leftmostdesc [j] = i ;
+ j = Front_parent [j] ;
+ DEBUG3 ((" go to j = "ID"\n", j)) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* compute memory and flop estimates */
+ /* ---------------------------------------------------------------------- */
+
+ nchains = 0 ; /* number of chains */
+ Chain_start [0] = 0 ; /* front 0 starts a new chain */
+ maxrows = 1 ;
+ maxcols = 1 ;
+ maxfrsize = 1 ;
+ dmaxfrsize = 1 ;
+ chain_npiv = 0 ; /* number of pivots in current chain */
+
+ /* ---------------------------------------------------------------------- */
+ /* simulate UMF_kernel_init */
+ /* ---------------------------------------------------------------------- */
+
+ /* Numeric->Memory usage estimate, in Units */
+ head_usage = 1 ; /* head marker (see UMF_mem_init_memoryspace) */
+ init_tail_usage = 2 ; /* tail marker (see UMF_mem_init_memoryspace) */
+ dusage = 3 ; /* head and tail markers */
+ dhead_usage = 1 ;
+
+ /* elements and tuples at tail*/
+ init_tail_usage += UMF_kernel_init_usage (Ap, Row_degree, n_row, n_col,
+ &dusage) ;
+
+ /* ] done using Row_degree */
+
+ ASSERT (UMF_is_permutation (Rperm_init, SWork->Ci, n_row, n_row)) ;
+
+ tail_usage = init_tail_usage ;
+ DEBUG2 (("tail_usage: "ID" (initial)\n", tail_usage)) ;
+ max_usage = head_usage + init_tail_usage ;
+ dmax_usage = dusage ;
+
+ Symbolic->num_mem_init_usage = max_usage ;
+
+ too_large = INT_OVERFLOW (dusage * sizeof (Unit)) ;
+ if (too_large)
+ {
+ /* Initial memory usage, for input matrix only, */
+ /* has encountered integer overflow. This is an error */
+ /* condition, but keep going to compute other statistics. */
+ Info [UMFPACK_VARIABLE_INIT_ESTIMATE] = dusage ; /* too large */
+ }
+ else
+ {
+ Info [UMFPACK_VARIABLE_INIT_ESTIMATE] = (double) max_usage ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* simulate UMF_kernel */
+ /* ---------------------------------------------------------------------- */
+
+ /* Use SWork->Ci as temporary workspace for link lists */
+ Link = SWork->Ci ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ Link [i] = EMPTY ;
+ }
+
+ dlnz = MIN (n_row, n_col) ; /* upper limit of nz in L (incl diag) */
+ dunz = dlnz ; /* upper limit of nz in U (incl diag) */
+ flops = 0 ; /* flop count upper bound */
+
+ DEBUG1 (("Umfpack symbolic, fronts: nfr = "ID"\n", nfr)) ;
+
+ for (i = 0 ; i < nfr ; i++)
+ {
+
+ fpivcol = Front_npivcol [i] ; /* # candidate pivot columns */
+ fallrows = SWork->Front_nrows [i] ; /* all rows (not just Schur comp*/
+ fallcols = SWork->Front_ncols [i] ; /* all cols (not just Schur comp*/
+ parent = Front_parent [i] ; /* parent in column etree */
+
+ DEBUG1 (("\nFront "ID" fpivcol "ID" fallrows "ID" fallcols "ID"\n",
+ i, fpivcol, fallrows, fallcols)) ;
+
+ /* determine the max size of the contribution block */
+ fpiv = MIN (fpivcol, fallrows) ; /* # pivot rows and cols */
+ frows = fallrows - fpiv ; /* max # rows in Schur comp. */
+ fcols = fallcols - fpiv ; /* max # cols in Schur comp. */
+
+ DEBUG1 ((" "ID" : fpiv "ID" frows "ID" fcols "ID" parent "ID"\n",
+ i, fpiv, frows, fcols, parent)) ;
+
+ /* UMF_analyze can generate 0-by-c sized frontal matrices */
+ ASSERT (fpiv >= 0 && fcols >= 0 && frows >= 0) ;
+
+ /* assemble all children of front i in column etree */
+ for (child = Link [i] ; child != EMPTY ; child = Link [child])
+ {
+ ASSERT (child >= 0 && child < i) ;
+ ASSERT (Front_parent [child] == i) ;
+ /* free the child element */
+ cp = MIN (Front_npivcol [child], SWork->Front_nrows [child]);
+ cr = SWork->Front_nrows [child] - cp ;
+ cc = SWork->Front_ncols [child] - cp ;
+ ASSERT (cp >= 0 && cr >= 0 && cc >= 0) ;
+ tail_usage -= GET_ELEMENT_SIZE (cr, cc) + 1 ;
+ dusage -= DGET_ELEMENT_SIZE (cr, cc) + 1 ;
+ /* remove it from tuple lists */
+ tail_usage -= (cr + cc) * UNITS (Tuple, 1) ;
+ dusage -= ((double) cr + (double) cc) * UNITS (Tuple, 1) ;
+ DEBUG2 (("tail_usage: "ID" (assembled "ID" of size "ID")\n",
+ tail_usage, child,
+ GET_ELEMENT_SIZE (cr, cc) + 1 + (cr + cc) * UNITS (Tuple, 1))) ;
+ }
+
+ /* the flop count excludes the BLAS2 calls during pivot search */
+ /* the assembly required to search a column, and assembly between */
+ /* frontal matrices. Those are "mushy" flops. */
+ /* The flop count computed here is "canonical". */
+
+ /* factorize the frontal matrix */
+ f = (double) fpiv ; /* # of pivots */
+ r = (double) frows ; /* # rows in Schur complement */
+ c = (double) fcols ; /* # cols in Schur complement */
+ flops += DIV_FLOPS * (f*r + (f-1)*f/2) /* scale pivot columns */
+ /* f outer products: */
+ + MULTSUB_FLOPS * (f*r*c + (r+c)*(f-1)*f/2 + (f-1)*f*(2*f-1)/6) ;
+
+ /* count nonzeros in L and U */
+ lf = (fpiv*fpiv-fpiv)/2 + fpiv*frows ; /* nz in L below diagonal */
+ uf = (fpiv*fpiv-fpiv)/2 + fpiv*fcols ; /* nz in U above diagonal */
+
+ /* store the f columns of L and f rows of U */
+ head_usage +=
+ UNITS (Entry, lf + uf) /* numerical values (excl diagonal) */
+ + UNITS (Int, frows + fcols + fpiv) ; /* indices (compressed) */
+
+ /* count nonzeros and memory usage in double precision */
+ dlf = (f*f-f)/2 + f*r ; /* nz in L below diagonal */
+ duf = (f*f-f)/2 + f*c ; /* nz in U above diagonal */
+ dlnz += dlf ;
+ dunz += duf ;
+ dh =
+ DUNITS (Entry, dlf + duf) /* numerical values (excl diagonal) */
+ + DUNITS (Int, r + c + f) ; /* indices (compressed) */
+ dusage += dh ;
+ dhead_usage += dh ;
+
+ if (parent != EMPTY)
+ {
+ /* create new element */
+ tail_usage += GET_ELEMENT_SIZE (frows, fcols) + 1 ;
+ dusage += DGET_ELEMENT_SIZE (frows, fcols) + 1 ;
+
+ /* place new element in tuple lists */
+ tail_usage += (frows + fcols) * UNITS (Tuple, 1) ;
+ dusage += (r + c) * UNITS (Tuple, 1) ;
+ DEBUG2 (("tail_usage: "ID" (create "ID" of size "ID")\n",
+ tail_usage, i,
+ GET_ELEMENT_SIZE (frows, fcols) + 1
+ + (frows + fcols) * UNITS (Tuple, 1))) ;
+
+ /* place in link list of parent */
+ Link [i] = Link [parent] ;
+ Link [parent] = i ;
+ }
+
+ /* keep track of peak Numeric->Memory usage */
+ max_usage = MAX (max_usage, head_usage + tail_usage) ;
+
+ /* max_usage may encounter integer overflow, so dmax_usage also kept. */
+ /* account for possible roundoff errors in dusage. */
+ /* Ignore NaN case. */
+ dusage *= (1.0 + MAX_EPSILON) ;
+ dusage = MAX (dusage,
+ (double) (head_usage + tail_usage) * (1.0 + MAX_EPSILON)) ;
+ dmax_usage = MAX (dmax_usage, dusage) ;
+ dhead_usage *= (1.0 + MAX_EPSILON) ;
+ dhead_usage = MAX (dhead_usage,
+ (double) head_usage * (1.0 + MAX_EPSILON)) ;
+
+ /* at most nb or chain_npiv pending pivots from old fronts */
+ maxoldpiv = MIN (nb, chain_npiv) ;
+ maxrows = MAX (maxrows, maxoldpiv + fallrows) ;
+ maxcols = MAX (maxcols, maxoldpiv + fallcols) ;
+
+ DEBUG1 ((" ID: chain_npiv "ID" fpiv "ID" fallrows "ID,
+ i, chain_npiv, fpiv, fallrows)) ;
+ DEBUG1 ((" fallcols "ID" maxoldpiv "ID" maxrows "ID" maxcols "ID"\n",
+ fallcols, maxoldpiv, maxrows, maxcols)) ;
+
+ chain_npiv += fpiv ;
+ if (parent != i+1)
+ {
+ /* this is the end of a chain */
+ Chain_maxrows [nchains] = maxrows ;
+ Chain_maxcols [nchains] = maxcols ;
+ /* Ignore NaN case. */
+ dmaxfrsize = MAX (dmaxfrsize, (double) maxrows * (double) maxcols) ;
+ maxfrsize = MAX (maxfrsize, maxrows * maxcols) ;
+ nchains++ ;
+ Chain_start [nchains] = i+1 ;
+ maxrows = 1 ;
+ maxcols = 1 ;
+ chain_npiv = 0 ;
+ }
+ }
+
+ dhead_usage = ceil (dhead_usage) ;
+ dmax_usage = ceil (dmax_usage) ;
+
+ tail_usage -= init_tail_usage ;
+
+ /* all tuples and elements are now deallocated */
+ DEBUG0 (("final tail_usage: "ID"\n", tail_usage)) ;
+ ASSERT (tail_usage == 0) ;
+
+ DEBUG1 (("dmaxfrsize %30.20g Int_MAX %30d\n", dmaxfrsize, Int_MAX)) ;
+
+ /* check if the frontal matrix is too big */
+ too_large = too_large || INT_OVERFLOW (dmaxfrsize * sizeof (Entry)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find the biggest frontal matrix, for all chains */
+ /* ---------------------------------------------------------------------- */
+
+ maxnrows = 1 ;
+ maxncols = 1 ;
+ for (i = 0 ; i < nchains ; i++)
+ {
+ maxnrows = MAX (maxnrows, Chain_maxrows [i]) ;
+ maxncols = MAX (maxncols, Chain_maxcols [i]) ;
+ }
+
+ /* information to keep for numeric factorization */
+ Symbolic->maxfrsize = maxfrsize ;
+ Symbolic->maxnrows = maxnrows ;
+ Symbolic->maxncols = maxncols ;
+ Symbolic->num_mem_usage_est = dmax_usage ;
+ Symbolic->num_mem_size_est = dhead_usage ;
+
+ /* ---------------------------------------------------------------------- */
+ /* estimate total memory usage in UMFPACK_numeric */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_set_stats (
+ Info,
+ Symbolic,
+ dmax_usage, /* estimated peak size of Numeric->Memory */
+ dhead_usage, /* estimated final size of Numeric->Memory */
+ flops, /* estimated "true flops" */
+ dlnz, /* estimated nz in L */
+ dunz, /* estimated nz in U */
+ dmaxfrsize, /* estimated largest front size */
+ (double) n_col, /* worst case Numeric->Upattern size */
+ (double) n_inner, /* max possible pivots to be found */
+ ESTIMATE) ;
+
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ for (i = 0 ; i < nchains ; i++)
+ {
+ DEBUG2 (("Chain "ID" start "ID" end "ID" maxrows "ID" maxcols "ID"\n",
+ i, Chain_start [i], Chain_start [i+1] - 1,
+ Chain_maxrows [i], Chain_maxcols [i])) ;
+ UMF_dump_chain (Chain_start [i],
+ SWork->Front_parent,
+ SWork->Front_npivcol,
+ SWork->Front_nrows,
+ SWork->Front_ncols,
+ nfr) ;
+ }
+ fpivcol = 0 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ fpivcol = MAX (fpivcol, Front_npivcol [i]) ;
+ }
+ DEBUG0 (("Max pivot cols in any front: "ID"\n", fpivcol)) ;
+ DEBUG1 (("Largest front: maxnrows "ID" maxncols "ID" maxfrsize "ID"\n",
+ maxnrows, maxncols, maxfrsize)) ;
+ DEBUG1 (("(savings "ID") nchains "ID"\n",
+ (maxnrows*maxncols) - maxfrsize, nchains)) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* is the problem too large? */
+ /* ---------------------------------------------------------------------- */
+
+ if (too_large)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_problem_too_large ;
+ error (&Symbolic, SWork) ;
+ return (UMFPACK_ERROR_problem_too_large) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* UMFPACK_symbolic was successful, return the object handle */
+ /* ---------------------------------------------------------------------- */
+
+ Symbolic->valid = SYMBOLIC_VALID ;
+ *SymbolicHandle = (void *) Symbolic ;
+
+ /* ---------------------------------------------------------------------- */
+ /* free workspace */
+ /* ---------------------------------------------------------------------- */
+
+ free_work (SWork) ;
+ /* Symbolic contains 10 objects */
+ DEBUG0 (("(3)Symbolic UMF_malloc_count - init_count = "ID"\n",
+ UMF_malloc_count - init_count)) ;
+ ASSERT (UMF_malloc_count == init_count + 10) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the time used by UMFPACK_*symbolic */
+ /* ---------------------------------------------------------------------- */
+
+ tend = umfpack_timer ( ) ;
+ Info [UMFPACK_SYMBOLIC_TIME] = MAX (0, tend - tstart) ;
+
+ return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+ SWorkType *SWork
+)
+{
+ ASSERT (SWork) ;
+
+ SWork->Ci = (Int *) UMF_free ((void *) SWork->Ci) ;
+ SWork->Front_npivcol = (Int *) UMF_free ((void *) SWork->Front_npivcol) ;
+ SWork->Front_nrows = (Int *) UMF_free ((void *) SWork->Front_nrows) ;
+ SWork->Front_ncols = (Int *) UMF_free ((void *) SWork->Front_ncols) ;
+ SWork->Front_parent = (Int *) UMF_free ((void *) SWork->Front_parent) ;
+ SWork->Front_cols = (Int *) UMF_free ((void *) SWork->Front_cols) ;
+
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_symbolic. Free all allocated memory. */
+
+PRIVATE void error
+(
+ SymbolicType **Symbolic,
+ SWorkType *SWork
+)
+{
+
+ free_work (SWork) ;
+ UMFPACK_free_symbolic ((void **) Symbolic) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_solve.c b/src/sparse-matrix/umfpack/umfpack_solve.c
new file mode 100644
index 0000000..9f949f1
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_solve.c
@@ -0,0 +1,258 @@
+/* ========================================================================== */
+/* === UMFPACK_solve ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Solves a linear system using the numerical factorization
+ computed by UMFPACK_numeric. See umfpack_solve.h for more details.
+
+ For umfpack_*_solve:
+ Dynamic memory usage: UMFPACK_solve calls UMF_malloc twice, for
+ workspace of size c*n*sizeof(double) + n*sizeof(Int), where c is
+ defined below. On return, all of this workspace is free'd via UMF_free.
+
+ For umfpack_*_wsolve:
+ Pattern is a workspace of size n Integers. The double array W must be
+ at least of size c*n, where c is defined below.
+
+ If iterative refinement is requested, and Ax=b, A'x=b or A.'x=b is being
+ solved, and the matrix A is not singular, then c is 5 for the real version
+ and 10 for the complex version. Otherwise, c is 1 for the real version and
+ 4 for the complex version.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_solve.h"
+
+#ifndef WSOLVE
+#include "umf_malloc.h"
+#include "umf_free.h"
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+#endif
+
+GLOBAL Int
+#ifdef WSOLVE
+UMFPACK_wsolve
+#else
+UMFPACK_solve
+#endif
+(
+ Int sys,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ double Xx [ ],
+#ifdef COMPLEX
+ double Xz [ ],
+#endif
+ const double Bx [ ],
+#ifdef COMPLEX
+ const double Bz [ ],
+#endif
+ void *NumericHandle,
+ const double Control [UMFPACK_CONTROL],
+ double User_Info [UMFPACK_INFO]
+#ifdef WSOLVE
+ , Int Pattern [ ],
+ double W [ ]
+#endif
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ NumericType *Numeric ;
+ Int n, i, irstep, status ;
+ double Info2 [UMFPACK_INFO], *Info, tstart, tend ;
+#ifndef WSOLVE
+ Int *Pattern, wsize ;
+ double *W ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get the amount of time used by the process so far */
+ /* ---------------------------------------------------------------------- */
+
+ tstart = umfpack_timer ( ) ;
+
+#ifndef WSOLVE
+#ifndef NDEBUG
+ init_count = UMF_malloc_count ;
+#endif
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ if (!Control)
+ {
+ irstep = UMFPACK_DEFAULT_IRSTEP ;
+ }
+ else if (SCALAR_IS_NAN (Control [UMFPACK_IRSTEP]))
+ {
+ irstep = UMFPACK_DEFAULT_IRSTEP ;
+ }
+ else
+ {
+ irstep = (Int) Control [UMFPACK_IRSTEP] ;
+ }
+
+ if (User_Info)
+ {
+ /* return Info in user's array */
+ Info = User_Info ;
+ for (i = UMFPACK_IR_TAKEN ; i <= UMFPACK_SOLVE_TIME ; 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 ;
+ }
+ }
+
+ Info [UMFPACK_STATUS] = UMFPACK_OK ;
+ Info [UMFPACK_SOLVE_FLOPS] = 0 ;
+
+ Numeric = (NumericType *) NumericHandle ;
+ if (!UMF_valid_numeric (Numeric))
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ;
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ Info [UMFPACK_NROW] = Numeric->n_row ;
+ Info [UMFPACK_NCOL] = Numeric->n_col ;
+
+ 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) ;
+ }
+ n = Numeric->n_row ;
+ if (Numeric->nnzpiv < n
+ || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+ {
+ /* turn off iterative refinement if A is singular */
+ /* or if U has NaN's on the diagonal. */
+ irstep = 0 ;
+ }
+
+ if (!Xx || !Bx
+#ifdef COMPLEX
+ || !Xz || !Bz
+#endif
+ )
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ if (sys >= UMFPACK_Pt_L)
+ {
+ /* no iterative refinement except for nonsingular Ax=b, A'x=b, A.'x=b */
+ irstep = 0 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate or check the workspace */
+ /* ---------------------------------------------------------------------- */
+
+#ifdef WSOLVE
+
+ if (!W || !Pattern)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ;
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+#else
+
+#ifdef COMPLEX
+ if (irstep > 0)
+ {
+ wsize = 10*n ; /* W, X, Z, S, Y, B2 */
+ }
+ else
+ {
+ wsize = 4*n ; /* W, X */
+ }
+#else
+ if (irstep > 0)
+ {
+ wsize = 5*n ; /* W, Z, S, Y, B2 */
+ }
+ else
+ {
+ wsize = n ; /* W */
+ }
+#endif
+
+ Pattern = (Int *) UMF_malloc (n, sizeof (Int)) ;
+ W = (double *) UMF_malloc (wsize, sizeof (double)) ;
+ if (!W || !Pattern)
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ (void) UMF_free ((void *) W) ;
+ (void) UMF_free ((void *) Pattern) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+#endif /* WSOLVE */
+
+ /* ---------------------------------------------------------------------- */
+ /* solve the system */
+ /* ---------------------------------------------------------------------- */
+
+ status = UMF_solve (sys, Ap, Ai, Ax, Xx, Bx,
+#ifdef COMPLEX
+ Az, Xz, Bz,
+#endif
+ Numeric, irstep, Info, Pattern, W) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* free the workspace (if allocated) */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef WSOLVE
+ (void) UMF_free ((void *) W) ;
+ (void) UMF_free ((void *) Pattern) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get the time used by UMFPACK_*solve */
+ /* ---------------------------------------------------------------------- */
+
+ Info [UMFPACK_STATUS] = status ;
+ if (status >= 0)
+ {
+ tend = umfpack_timer ( ) ;
+ Info [UMFPACK_SOLVE_TIME] = MAX (0, tend - tstart) ;
+ }
+
+ return (status) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_symbolic.c b/src/sparse-matrix/umfpack/umfpack_symbolic.c
new file mode 100644
index 0000000..e51a0eb
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_symbolic.c
@@ -0,0 +1,34 @@
+/* ========================================================================== */
+/* === UMFPACK_symbolic ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Performs a symbolic factorization.
+ See umfpack_symbolic.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_symbolic
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ void **SymbolicHandle,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+)
+{
+ Int *Qinit = (Int *) NULL ;
+ return (UMFPACK_qsymbolic (n_row, n_col, Ap, Ai, Qinit, SymbolicHandle,
+ Control, Info)) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/umfpack_timer.c b/src/sparse-matrix/umfpack/umfpack_timer.c
new file mode 100644
index 0000000..29c9b5d
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_timer.c
@@ -0,0 +1,70 @@
+/* ========================================================================== */
+/* === umfpack_timer ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+ User-callable. Returns the time in seconds used by the process. BE
+ CAREFUL: if you compare the run time of UMFPACK with other sparse matrix
+ packages, be sure to use the same timer. See umfpack_timer.h for details.
+*/
+
+#ifdef GETRUSAGE
+
+/* -------------------------------------------------------------------------- */
+/* use getrusage for accurate process times (and no overflow) */
+/* -------------------------------------------------------------------------- */
+
+/*
+ This works under Solaris, SGI Irix, Linux, IBM RS 6000 (AIX), and Compaq
+ Alpha. It might work on other Unix systems, too. Includes both the "user
+ time" and the "system time". The system time is the time spent by the
+ operating system on behalf of the process, and thus should be charged to
+ the process.
+*/
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+double umfpack_timer ( void )
+{
+ struct rusage ru ;
+ double user_time, sys_time ;
+
+ (void) getrusage (RUSAGE_SELF, &ru) ;
+
+ user_time =
+ ru.ru_utime.tv_sec /* user time (seconds) */
+ + 1e-6 * ru.ru_utime.tv_usec ; /* user time (microseconds) */
+
+ sys_time =
+ ru.ru_stime.tv_sec /* system time (seconds) */
+ + 1e-6 * ru.ru_stime.tv_usec ; /* system time (microseconds) */
+
+ return (user_time + sys_time) ;
+}
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* Generic ANSI C: use the ANSI clock function */
+/* -------------------------------------------------------------------------- */
+
+/* This is portable, but may overflow. On Sun Solaris, when compiling in */
+/* 32-bit mode, the overflow occurs in only 2147 seconds (about 36 minutes). */
+
+#include <time.h>
+
+double umfpack_timer ( void )
+{
+ return (((double) (clock ( ))) / ((double) (CLOCKS_PER_SEC))) ;
+}
+
+#endif
+
diff --git a/src/sparse-matrix/umfpack/umfpack_transpose.c b/src/sparse-matrix/umfpack/umfpack_transpose.c
new file mode 100644
index 0000000..db50e36
--- /dev/null
+++ b/src/sparse-matrix/umfpack/umfpack_transpose.c
@@ -0,0 +1,113 @@
+/* ========================================================================== */
+/* === UMFPACK_transpose ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.0 (Apr 11, 2002), Copyright (c) 2002 by Timothy A. */
+/* Davis. All Rights Reserved. See README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
+/* -------------------------------------------------------------------------- */
+
+/*
+
+ User callable. Computes a permuted transpose, R = (A (P,Q))' in MATLAB
+ notation. See umfpack_transpose.h for details. A and R can be rectangular.
+ The matrix A may be singular.
+ The complex version can do transpose (') or array transpose (.').
+
+ Dynamic memory usage:
+
+ A single call to UMF_malloc is made, for a workspace of size
+ max (n_row,n_col,1) * sizeof(Int). This is then free'd on return,
+ via UMF_free.
+
+*/
+
+#include "umf_internal.h"
+#include "umf_transpose.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_transpose
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ], /* size n_col+1 */
+ const Int Ai [ ], /* size nz = Ap [n_col] */
+ const double Ax [ ], /* size nz, if present */
+#ifdef COMPLEX
+ const double Az [ ], /* size nz, if present */
+#endif
+
+ const Int P [ ], /* P [k] = i means original row i is kth row in A(P,Q)*/
+ /* P is identity if not present */
+ /* size n_row, if present */
+
+ const Int Q [ ], /* Q [k] = j means original col j is kth col in A(P,Q)*/
+ /* Q is identity if not present */
+ /* size n_col, if present */
+
+ Int Rp [ ], /* size n_row+1 */
+ Int Ri [ ], /* size nz */
+ double Rx [ ] /* size nz, if present */
+#ifdef COMPLEX
+ , double Rz [ ] /* size nz, if present */
+ , Int do_conjugate /* if true, then to conjugate transpose */
+ /* otherwise, do array transpose */
+#endif
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int status, *W, nn ;
+
+#ifndef NDEBUG
+ init_count = UMF_malloc_count ;
+ UMF_dump_start ( ) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate workspace */
+ /* ---------------------------------------------------------------------- */
+
+ nn = MAX (n_row, n_col) ;
+ nn = MAX (nn, 1) ;
+ W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ if (!W)
+ {
+ ASSERT (UMF_malloc_count == init_count) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ ASSERT (UMF_malloc_count == init_count + 1) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* C = (A (P,Q))' or (A (P,Q)).' */
+ /* ---------------------------------------------------------------------- */
+
+ status = UMF_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, n_col, Rp, Ri, Rx,
+ W, TRUE
+#ifdef COMPLEX
+ , Az, Rz, do_conjugate
+#endif
+ ) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* free the workspace */
+ /* ---------------------------------------------------------------------- */
+
+ (void) UMF_free ((void *) W) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+
+ return (status) ;
+}
+
diff --git a/src/sparse-matrix/umfpack/wrap_umf_ltsolve.c b/src/sparse-matrix/umfpack/wrap_umf_ltsolve.c
new file mode 100644
index 0000000..e9642bd
--- /dev/null
+++ b/src/sparse-matrix/umfpack/wrap_umf_ltsolve.c
@@ -0,0 +1,2 @@
+#define CONJUGATE_SOLVE
+#include "umf_ltsolve.c"
diff --git a/src/sparse-matrix/umfpack/wrap_umf_utsolve.c b/src/sparse-matrix/umfpack/wrap_umf_utsolve.c
new file mode 100644
index 0000000..37e5c0a
--- /dev/null
+++ b/src/sparse-matrix/umfpack/wrap_umf_utsolve.c
@@ -0,0 +1,2 @@
+#define CONJUGATE_SOLVE
+#include "umf_utsolve.c"
diff --git a/src/sparse-matrix/umfpack/wrap_umfpack_wsolve.c b/src/sparse-matrix/umfpack/wrap_umfpack_wsolve.c
new file mode 100644
index 0000000..c02853a
--- /dev/null
+++ b/src/sparse-matrix/umfpack/wrap_umfpack_wsolve.c
@@ -0,0 +1,2 @@
+#define WSOLVE
+#include "umfpack_solve.c"